Swift Dictionary issues

(ndelic) #1

If I have a Swift dictionary initialized like this:

let dict = [String: Int]()

I can iterate through it like this:

XCode:

for item in dict {
  let itemKey: String = item.key
  let itemValue: Int = item.value
  //  Do something...
}

Fire/VS2017 (.2373) -> Android/Java/.NET

for item in dict {
  let itemKey: String = item.Item1
  let itemValue: Int = item.Item2
  //  Do something...
}

I understand there are differences here (key and value vs. Item1 and Item2) because tuples behave differently in Apple Swift and Silver.

However, I tried to unify the syntax so it would be the same on all platforms, like this:

for item: (key: String, value: Int) in dict {
  let itemKey: String = item.key
  let itemValue: Int = item.value
  //  Do something...
}

This compiles fine in XCode and Fire for Java, but it doesn’t compile in VS2017 for .NET because the compiler complains that it cannot cast Tuple<String, Int> (dictionary item) as ValueTuple<String, Int> (the (key: String, value: Int) syntax). I think this is a tad inconsistent, given that Java code compiles fine, so it’s reasonable to expect that .NET code would, too. Then again, I’m not an expert on various “same looking class but possibly completely different behavior” that you guys have to take into account on different platforms, which is why probably the above stuff happens.

Anyway, is there any way we can have this:

for item in dict {
  let itemKey: String = item.key
  let itemValue: Int = item.value
  //  Do something...
}

or this:

for item (key: String, value: Int) in dict {
  let itemKey: String = item.key
  let itemValue: Int = item.value
  //  Do something...
}

compile in Fire/VS for both Java (it already does) and .NET (it doesn’t at the time)? Right now it’s a bit of maintenance overkill because I have two different files (Cocoa-Java and .NET) with protocol extensions to access these values, which means that for a particular business logic that could otherwise be 100% cross platform, I must maintain approx. 0,01% of platform specific code.

(marc hoffman) #2

I’ll see if I can rename those.

hmm, this compiles fine for me, for .NET:

let dict = [String: Int]()
for item: (key: String, value: Int) in dict {
	let itemKey: String = item.key // H11 Local variable "itemKey" is assigned to but never read
	let itemValue: Int = item.value // H11 Local variable "itemValue" is assigned to but never read
  //  Do something...
}

what am I missing?

(RemObjects) #3

Thanks, logged as bugs://82127

(ndelic) #4

I’ll try to prepare a test project for .NET with code from my project.

1 Like
(ndelic) #5

Something strange is going on. As soon as I move the problematic code files into a separate project, they also compile on .NET. However, in my project they don’t compile. :frowning: It’ll take me some time to prepare an uncompilable project.

1 Like
(ndelic) #6

Marc

I prepared the test project, it fails with the following messages:

Given that it’s my project’s code, I don’t want to post it here. Where can I send it to?

1 Like
(marc hoffman) #7

support@, please…

(ndelic) #8

Sent.

1 Like
(RemObjects) #9

Thanks, logged as bugs://82139

(marc hoffman) #10

Very odd. it reproduces in your project, but I still cannot see it in a simple test case, even with:

public typealias Translations = [String: TranslationItems]
public typealias TranslationItems = [String: String]

guard let newTranslations: Translations = Translations() else {
    return
}

for item: (key: String, value: TranslationItems) in newTranslations {
    let itemKey: String = item.key
    let itemValue = item.value
  //  Do something...
}

very strange. Carlo will need to have a look based on your test case…

(ndelic) #11

I’m not sure if this helps, but just in case…

Code below compiles fine on all platforms: XCode, Fire/Android and VS/WPF. The difference is that now I have a (direct) class instance stored in the dictionary. Unlike the test project that doesn’t compile, which stores typealiases. I had some issues with typealiases in the past but managed to bypass them somehow until now.

public class RemoteService {
    public var name: String = ""
    public var port: Int = 0
}

public class RemoteHost {
  var addresses = [String]()
  var name: String = ""
  var services = [String: RemoteService]()
}

let hosts: [String: RemoteHost] = getActiveHosts()

for kvHost: (key: String, value: RemoteHost) in hosts {

  if kvHost.key == "someValue" && kvHost.value.name == "someOtherValue" {
    //  Do something
  }
}

I hope this helps in any way.

(Carlo Kok) #12

What happens is that we have Tuple and ValueTuple and if it’s available, it uses VAlueType, you want to set both libraries to have the same framework version, ValueTuple is available from :

.NET Framework

4.8 4.7.2 4.7.1 4.7

(RemObjects) #13

bugs://82139 got closed with status nochangereq.

(Carlo Kok) #14

Can you try this and let me know if it works properly now for you, with named tuples and everything?)

(ndelic) #15

What do you mean by “this”?

(Carlo Kok) #16

Yeah I think I misread the original bug. The .key, .value thing should just work, not item1, item2. I’ll get back to you when I know more.

(RemObjects) #17

bugs://82127 got closed with status fixed.

(ndelic) #18

While you’re working on dictionaries, can you also check this out? I reported it a week ago, but never received any feedback.

(Carlo Kok) #19

Logged. Seems we missed that.