It seems like you can't use named tuples in the shorthand notation of Dictionary. Is that so?
E.g.:
var dt = Dictionary<Int, (x:Double, y:Double)>()
var dtShort = [Int: (Double, Double)]()
var dtShortNamed = [Int: (x:Double, y:Double)]()
The first two lines work, the third triggers an error "Expected member name or constructor call after type name"
Is this correct, or am I missing something?
You are correct that it doesn't seem to work that way in Xcode 6 GM or Xcode 6.1 Beta 2.
It does work if you use a typealias though:
typealias NamedTuple = (x:Double, y:Double)
var dtShortNamed = [Int: NamedTuple]()
But, in that case, you might as well just use your first example:
var dt = Dictionary<Int, (x:Double, y:Double)>()
Related
I wanted to create a global variable called result that uses 5 string concatenations to create a string containing 9 times the string start, separated by commas.
I have two pieces of code, only the second one declares a global variable.
For some reason it's not registering easily in my brain... Is it just that i used a let in so result in the first piece of code is a local variable? Is there a more detailed explanation for this?
let start = "ab";;
let result = start ^ "," in
let result = result ^ result in
let result = result ^ result in
let result = result ^ result in
let result = result ^ start in
result;;
- : string = "ab,ab,ab,ab,ab,ab,ab,ab,ab"
let result =
let result = start ^ "," in
let result = result ^ result in
let result = result ^ result in
let result = result ^ result in
let result = result ^ start in
result;;
val result : string = "ab,ab,ab,ab,ab,ab,ab,ab,ab"
Let me to be a little bit boring person. There are no local and global variables in OCaml. This concept came from languages with different scoping rules. Also, the word "variable" itself should be taken with care. Its meaning was perverted by C-like languages. The original, mathematical, meaning of this word corresponds to a name of some mathematical object, that is used inside a formula, that represent a range of such values. In C-like languages, a variable is confused with the memory cell, that can change in time. So, to avoid the confusion let's use a more accurate terminology. Let's use word name instead of variable. Since, variables... sorry names are not memory cells, there is nothing to create. When you're using one of the let syntaxes, you're actually creating a binding, i.e., an association between a name and a value. The let <name> = <expr-1> in <expr-2> binds a value of the in the scope of the <expr-2> expression. The let <name> = <expr-1> in <expr-2> is by itself is also an expression, so, for example <expr-2> can also contain let ... in ... constructs inside, e.g.,
let a = 1 in
let b = a + 1 in
let c = b + 1 in
a + b + c
I especially, indented the code in non-idiomatic way to highlight the syntactic structure of the expression. OCaml also allows to use a name, that is already bound in the scope. The new binding will hide the existing one (that is not allowed in C, for example), e.g.,
let a = a + 1 in
let a = a + 1 in
let a = a + 1 in
a + a + a
Finally, the top-level (aka module level) let-binding (called definition in OCaml parlance), has the syntax: let <name> = <expr>, note that there is no in here. The definition binds the <name> to a result of the evaluation of <expr> in the lexical scope that extends form the point of definition to the end of the enclosing module. When you're implementing a module, you must use let <name> = <expr> to bind your code to names (you may omit name by using _). It is a little bit different from the interactive toplevel (interactive ocaml program), that actually accepts an expression, and evaluates it. For example,
let result = start ^ "," in
let result = result ^ result in
let result = result ^ result in
let result = result ^ result in
let result = result ^ start in
result
Is not a valid OCaml program (something that can be put into an ml file and compiled). Because it is an expression, not a module definition.
Is it just that i used a let in so result in the first piece of code is a local variable?
Pretty much. The syntax to define a global variable is let variable = expression without an in. The syntax to define a local variable is let variable = expression in expression which will define variable local to the expression after the in.
When you have let ... in, you're declaring a local variable. When you have just let by itself (at the top level of a module), you're declaring a global name of the module. (That is, a name that can be exported from the module.)
Your first example consists entirely of let ... in. So there is no top-level name declared.
Your second example has one let by itself, followed by several occurrences of let ... in. So it declares a top-level name result.
can anyone explain why line 1 works to create an empty swift dictionary but line 2 doesn't when i try to create a swift dictionary with int key and tuple of double values .... how should it be done?
var testDic2 = [Int:Double]()
var testDic3 = [Int:(Double,Double)]()
I've tried various combinations in playgrounds and the only version where it doesnt give me a compiler error is as follows
var possibleTips = [Int(): (tipAmt:Double(), total:Double())]
but im not sure this last form is declaring the dictionary as i intend it (ie as per testDict3 above)
The compiler isn't sure how to instantiate the type in your second and third example. Instead, you can declare the type and use an empty dictionary initializer:
var testDic:[Int:(Double,Double)] = [:]
I'm trying to insert new key-value pair in dictionary, which nested in another one Dictionary:
var dict = Dictionary<Int, Dictionary<Int, String>>()
dict.updateValue([1 : "one", 2: "two"], forKey: 1)
dict[1]?[1] // {Some "one"}
if var insideDic = dict[1] {
// it is a copy, so I can't insert pair this way:
insideDic[3] = "three"
}
dict // still [1: [1: "one", 2: "two"]]
dict[1]?[3] = "three" // Cannot assign to the result of this expression
dict[1]?.updateValue("three", forKey: 3) // Could not find a member "updateValue"
I believe should be a simple way to handle it, but I spent an hour and still can't figure it out.
I can use NSDictionary instead, but I really like to understand how I should manage nested Dictionaries in Swift?
Dictionarys are value types so are copied on assignment. As a result you are going to have to get the inner dictionary (which will be a copy), add the new key, then re-assign.
// get the nested dictionary (which will be a copy)
var inner:Dictionary<Int, String> = dict[1]!
// add the new value
inner[3] = "three"
// update the outer dictionary
dict[1] = inner
println(dict) // [1: [1: one, 2: two, 3: three]]
You could use one of the new utility libraries such as ExSwift to make this a bit simpler:
dict[1] = dict[1]!.union([3:"three"])
This uses the union method that combines two dictionaries.
I'm trying to convert this objc code to swift:
CGContextRef contextRef = CGBitmapContextCreate(NULL,
proposedRect.size.width,
proposedRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
colorSpaceRef,
(CGBitmapInfo)kCGImageAlphaPremultipliedFirst);
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:contextRef flipped:NO];
So far I ended up with this:
var bitmapContext: CGContext = CGBitmapContextCreate(data, UInt(proposedRect.width), UInt(proposedRect.height), CGImageGetBitsPerComponent(image), 0, colorSpace, CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.toRaw()))
let context = NSGraphicsContext(graphicsPort: bitmapContext, flipped: false)
The problem is that CGBitmapContextCreate returns CGContext type and NSGraphicsContext initializer accepts graphicsPort as CMutableVoidPointer type. So how can I convert CGContext to CMutableVoidPointer?
related reverse type casting found here, but it didn't provide much help to me
How to convert COpaquePointer in swift to some type (CGContext? in particular)
I ended up with the reinterpretCast function returning intermediate Int variable for the bitmapContext address.
var bitmapContext: CGContext = CGBitmapContextCreate(...)
let bitmapContextAddress: Int = reinterpretCast(bitmapContext)
let bitmapContextPointer: CMutableVoidPointer = COpaquePointer(UnsafePointer<CGContext>(bitmapContextAddress))
let context = NSGraphicsContext(graphicsPort: bitmapContextPointer, flipped: false)
The documentation here:https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/InteractingWithCAPIs.html
states the following:
When a function is declared as taking a CMutableVoidPointer argument,
it can accept the same operands as CMutablePointer for any type
Type.
From that, it should work like this:
var p: CMutablePointer<CGContext> = &bitmapContext
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:p flipped:NO];
Extended practically, you should be able to pass in &bitmapContext directly to a CMutableVoidPointer argument.
Swift doesn't have "pointers" in the C sense.
So I started a project in Swift, and I've come to this problem:
this code works:
var dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
println(dictionary)
dictionary["c"] = "newValOfC"
println(dictionary)
and this doesn't:
var dictionary = [:]
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
println(dictionary)
dictionary["c"] = "newValOfC"
println(dictionary)
Gives an error:
Playground execution failed: error: <REPL>:35:17: error: cannot assign to the result of this expression
dictionary["c"] = "newValC"
~~~~~~~~~~~~~~~ ^
Notice that this is not a constant value
So why doesn't the line
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
give an error?
Since the context does not provide enough information to infer the type, you'll need to explicitly name it as a dictionary, otherwise swift assumes it is an NSDictionary (I'm not clear on why though. I assume for better obj-c compatibility):
The following code all works:
// Playground
import UIKit
var str:NSString = "Hello, playground"
var d0 = [:]
var d1: Dictionary = [:]
d0.setValue(UIWebView(), forKey: "asdf")
d1["asdf"] = 1
d1["qwer"] = "qwer"
Okay, I found it, the problem is that by initializing an empty dictionary, the type inference gets a little crazy.
You'll need this code:
var dictionary = Dictionary<String, String>()
instead of
var dictionary = [:]
but that still does not explain why the line
dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
does not give an error
And referring to Swift Language Guide, the
dictionary = [:]
syntax is correct "if the context already provides type information".
The big difference is that
var dictionary = [:]
doesn't give any chance the compiler to infer the right type, whereas
var dictionary = ["a":"valueOfA","b":"valueOfB","c":"valueOfC"]
does.
Actually it looks like the first line produces a __NSDictionaryI instance, whereas the second one produces a Dictionary<String,String as expected.
From The Swift Programming Language book
If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [:] (a colon inside a pair of square brackets):
which means the first line is ambiguous.
The [:] syntax only works if the current context has enough information to be able to infer what the types are. Here are a few ways where the context is known...
As has been mentioned already, the code below works because it can be inferred that the keys and values are strings:
var dictionary = [ "a" : "valueOfA" , "b" : "valueOfB" , "c" : "valueOfC" ]
A dictionary passed into a function has a known context:
func dictionaryFunc(var dictionary : Dictionary<String, String>) {
// Do stuff with the dictionary
}
In both cases, the key/value types for the dictionary are now known, so you could do this to create a new dictionary with the same variable name...
dictionary = [:]
In the first case, if you used the [:] syntax after the declaration you would be erasing the contents of the original dictionary. In the second case, dictionaries get copied when they get passed into functions, so using [:] would only be erasing the copy.
In Swift 2.0 I'm using this:
var dictionary = [String:String]()
dictionary["key1"] = "value1"