3

Given a struct S defined in this way

struct S {
    let a : String 
    let b : Int 
    let c : Bool 
}

and a function sConstructorFun

func sConstructorFun(#a:String, #b:Int, #c:Bool) -> S { 
    return S(a:a, b:b, c:c) 
}

I can use both sConstructorFun(a:"", b:1, c:false) and S(a:"", b:1, c:false) to get the following S value (as the REPL outputs it)

S = {
  a = ""
  b = 1
  c = false
}

So S and sConstructorFun have the very same interface and unsurprisingly return the same result.

However, a sFactory function defined as follows

func sFactory(f:(String, Int, Bool) -> S) -> S {
    return f("foo", 42, false) 
}

can only be used with the sConstructorFun but not with S directly:

REPL> sFactory(sConstructorFun) 
$R2: S = {
  a = "foo"
  b = 42
  c = false
}

and

REPL> sFactory(S) 
repl.swift:18:1: error: cannot invoke 'sFactory' with no arguments
sFactory(S)
^
repl.swift:18:9: note: expected an argument list of type '((String, Int, Bool) -> S)'
 sFactory(S)
         ^

Is there any way of using the default constructor of a struct (S in this example) as a function (without defining a new function/closure to do so)?

4
  • It is not clear to me what you mean with S = { a = "", b = 1, c = false }. S is the struct, then you use S as a left value. The syntax does not appear to be a valid Swift construct Commented Feb 16, 2015 at 18:08
  • @MatteoPiombo that's how the REPL outputs structs: ` 18> S(a:"foo", b:1, c:false) $R3: S = { a = "foo" b = 1 c = false } ` Commented Feb 16, 2015 at 18:21
  • SORRY! I cancelled a suggested edit, suggesting to change func sConstructorFun(#a:String, #b:Int, #c:Bool) -> S to func sConstructorFun(a a:String, b b:Int, c c:Bool) -> S because I thought that means something different. I'm really sorry about that and I will now reapply that edit. Commented Feb 16, 2015 at 19:53
  • posted as rdar://19849369 || openradar.appspot.com/19849369 Commented Feb 16, 2015 at 20:09

2 Answers 2

2

You just need to put the default constructor inside of a closure and pass that to the sFactory function. Try this:

let f = { S(a: $0, b: $1, c: $2) }

func sFactory(f:(String, Int, Bool) -> S) -> S {
    return f("foo", 42, false) 
}

let s = sFactory(f)

println("s = (a: \(s.a), b: \(s.b), c: \(s.c))") // S = (a: foo, b: 42, c: false)
Sign up to request clarification or add additional context in comments.

3 Comments

that's defining a new function f which is to my sConstructorFun just without labelled arguments. It does save some typing though. Clarified the question.
Joe Groff, a Swift developer just confirmed via Twitter that it's not possible at the moment and the easiest way is actually do define a new function wrapping the call :-(. I will therefore accept your answer.
I think the problem is that if you just use the letter S, Swift doesn't know what you want to do with it. You could be trying to pass the type as a parameter, or doing any number of other things with it. I'm curious, though, is that something that is common in other programming languages? Are there languages where you can pass the name of a type to a function and it will infer that you are trying to call a constructor? It would be kinda cool...
0

Not very clear to me your intent, but maybe you are looking for constructors like these:

extension S {
    init (f: (a: String, b: Int, c: Bool) -> S) {
        self = f(a: "foo", b: 1, c: true)
    }

    init(f: () -> S) {
        self = f()
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.