[Pitch] Unifying init parameters with properties


(Jon Hull) #1

Since we know the types of the properties, how about we replace the type in the signature with either an indication that the property should be automatically set, or better yet, the property which should be set:

class Foo
{
  let foo : String
  let bar : String
  let barCount : Int
  let baz : Int

  init(foo: self.foo, bar: self.bar, baz: self.baz)
  {
    self.barCount = bar.characters.count
  }
}

That way you don’t always have to have the init’s parameter names match the names of the properties they set (even though they often would). We could also allow a leading dot as a shorthand for ‘self.’

  init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my preference. In either case, the generated interface would show the actual type.

  // init(foo: String, bar: String, baz: Int)

Thanks,
Jon

···

This is a common pattern for initialisers at the moment:

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(foo: String, bar: String, baz: Int)

{

self.foo = foo

self.bar = bar

self.baz = baz

barCount = bar.characters.count

}

}

This involves a lot of using 'self.'. For those who prefer not to use
'self.' explicitly everywhere, this is probably the main place it gets
used. It's a lot of boilerplate code.

How would it be if, like default variables, we could pack some of that
information into the argument tuple, and unify parameters with properties
immediately?

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(self.foo: String, self.bar: String, self.baz: Int)

{

barCount = bar.characters.count

}

}

Less boilerplate, more focus on the properties which need to be generated.

Thoughts?


(Yogev Sitton) #2

This is an interesting idea.
Although I didn’t like this at first read - it will remove a lot of generic init methods from my code that all they do is just fill properties with values.

···

Since we know the types of the properties, how about we replace the type in the signature with either an indication that the property should be automatically set, or better yet, the property which should be set:

class Foo
{
let foo : String
let bar : String
let barCount : Int
let baz : Int

init(foo: self.foo, bar: self.bar, baz: self.baz)
{
self.barCount = bar.characters.count
}
}

That way you don’t always have to have the init’s parameter names match the names of the properties they set (even though they often would).We could also allow a leading dot as a shorthand for ‘self.’

init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my preference.In either case, the generated interface would show the actual type.

// init(foo: String, bar: String, baz: Int)

Thanks,
Jon

> This is a common pattern for initialisers at the moment: class Foo { let foo : String let bar : String let barCount : Int let baz : Int init(foo: String, bar: String, baz: Int) { self.foo = foo self.bar = bar self.baz = baz barCount = bar.characters.count } } This involves a lot of using 'self.'. For those who prefer not to use 'self.' explicitly everywhere, this is probably the main place it gets used. It's a lot of boilerplate code. How would it be if, like default variables, we could pack some of that information into the argument tuple, and unify parameters with properties immediately? class Foo { let foo : String let bar : String let barCount : Int let baz : Int init(self.foo: String, self.bar: String, self.baz: Int) { barCount = bar.characters.count } } Less boilerplate, more focus on the properties which need to be generated. Thoughts?


(David Sweeris) #3

I think I like the idea... However IMHO this really feels like something that should be part of a macro system, not a "proper" language feature.

- Dave Sweeris

···

On Apr 16, 2016, at 08:17, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

Since we know the types of the properties, how about we replace the type in the signature with either an indication that the property should be automatically set, or better yet, the property which should be set:

class Foo
{
  let foo : String
  let bar : String
  let barCount : Int
  let baz : Int

  init(foo: self.foo, bar: self.bar, baz: self.baz)
  {
    self.barCount = bar.characters.count
  }
}

That way you don’t always have to have the init’s parameter names match the names of the properties they set (even though they often would). We could also allow a leading dot as a shorthand for ‘self.’

  init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my preference. In either case, the generated interface would show the actual type.

  // init(foo: String, bar: String, baz: Int)

Thanks,
Jon

This is a common pattern for initialisers at the moment:

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(foo: String, bar: String, baz: Int)

{

self.foo = foo

self.bar = bar

self.baz = baz

barCount = bar.characters.count

}

}

This involves a lot of using 'self.'. For those who prefer not to use
'self.' explicitly everywhere, this is probably the main place it gets
used. It's a lot of boilerplate code.

How would it be if, like default variables, we could pack some of that
information into the argument tuple, and unify parameters with properties
immediately?

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(self.foo: String, self.bar: String, self.baz: Int)

{

barCount = bar.characters.count

}

}

Less boilerplate, more focus on the properties which need to be generated.

Thoughts?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #4

-1 on this. After the parameter declaration we expect to see a type of that parameter. I don't think we should break Swift method declarations for this feature. I prefer to see information about parameter types in func/init declaration. I don't want to scroll up to the start of class declaration to find out the type of parameter.

And, why in this case we need these foo: bar: at all?
We had a discussion earlier in this thread about such variant:

class Foo
{
let foo : String
let bar : String
let barCount : Int
let baz : Int

init(self.foo, self.bar, self.baz) // just self.foo etc, no parameter labels at ll
{
self.barCount = bar.characters.count
}

But I also think this is not OK to not have a types of parameters in init.

···

On 16.04.2016 16:17, Jonathan Hull via swift-evolution wrote:

Since we know the types of the properties, how about we replace the type in
the signature with either an indication that the property should be
automatically set, or better yet, the property which should be set:

class Foo
{
let foo : String
let bar : String
let barCount : Int
let baz : Int

init(foo: self.foo, bar: self.bar, baz: self.baz)
{
self.barCount = bar.characters.count
}

That way you don’t always have to have the init’s parameter names match the
names of the properties they set (even though they often would). We could
also allow a leading dot as a shorthand for ‘self.’

init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my preference.
In either case, the generated interface would show the actual type.

// init(foo: String, bar: String, baz: Int)

Thanks,
Jon

This is a common pattern for initialisers at the moment:

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(foo: String, bar: String, baz: Int)

{

self.foo = foo

self.bar = bar

self.baz = baz

barCount = bar.characters.count

}

}

This involves a lot of using 'self.'. For those who prefer not to use
'self.' explicitly everywhere, this is probably the main place it gets
used. It's a lot of boilerplate code.

How would it be if, like default variables, we could pack some of that
information into the argument tuple, and unify parameters with properties
immediately?

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(self.foo: String, self.bar: String, self.baz: Int)

{

barCount = bar.characters.count

}

}

Less boilerplate, more focus on the properties which need to be generated.

Thoughts?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #5

I agree with the intent of this, but perhaps not the solution; sticking with the original example, simply being able to have an implied initialiser for classes, as we have for structs, would be enough, for example:

class Foo {
  let foo:String
  let bar:String
  let baz:Int

  var barCount:Int { return self.bar.characters.count } // Computed property, could be lazy instead I think?

  // Implied init(foo:String, bar:String, baz:Int)
}

Personally I’m not a fan of the syntax, I wonder if an #autoinit or such directive could be used to indicate properties that should be initialised automatically where possible, like so:

class Foo {
  #autoInit let foo:String
  #autoInit let bar:String
  #autoInit let baz:Int
    let barCount:Int

  init(foo:String, bar:String, baz:Int) {
    // foo, bar, baz handled behind the scenes
    self.barCount = bar.characters.count
  }
}

(or it could be on the parameters of the init function, might be clearer that way)

Just an idea anyway

···

On 16 Apr 2016, at 14:17, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

Since we know the types of the properties, how about we replace the type in the signature with either an indication that the property should be automatically set, or better yet, the property which should be set:

class Foo
{
  let foo : String
  let bar : String
  let barCount : Int
  let baz : Int

  init(foo: self.foo, bar: self.bar, baz: self.baz)
  {
    self.barCount = bar.characters.count
  }
}

That way you don’t always have to have the init’s parameter names match the names of the properties they set (even though they often would). We could also allow a leading dot as a shorthand for ‘self.’

  init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my preference. In either case, the generated interface would show the actual type.

  // init(foo: String, bar: String, baz: Int)

Thanks,
Jon

This is a common pattern for initialisers at the moment:

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(foo: String, bar: String, baz: Int)

{

self.foo = foo

self.bar = bar

self.baz = baz

barCount = bar.characters.count

}

}

This involves a lot of using 'self.'. For those who prefer not to use
'self.' explicitly everywhere, this is probably the main place it gets
used. It's a lot of boilerplate code.

How would it be if, like default variables, we could pack some of that
information into the argument tuple, and unify parameters with properties
immediately?

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(self.foo: String, self.bar: String, self.baz: Int)

{

barCount = bar.characters.count

}

}

Less boilerplate, more focus on the properties which need to be generated.

Thoughts?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #6

-1 on #autoInit for properties declaration. Init should explicitly shows what parameters it will get and what will be assiged. I believe in case we want this feature, "self." prefix must be in init declaration in parameter list, with or without type(I prefer with type):

init( self.foo: String, self.bar: String, baz: Int){..}

or

init( self.foo, self.bar, baz: Int){..}

In this case IMO it is obvious that this init will set self.foo&self.bar by provided values from caller. And it is clear(in first variant) what is the types of parameters for init(let's imaging a class with long list of properties/internal structs/classes/enums, number of initializers then. And you see init( self.foo, self.bar, baz: Int) - what is the type of first parameter for this initializer? You have to scroll up to defenition of self.foo, then find self.bar definition etc. This is why I prefer explicit type declaration in init. Also this protects against automatic change of init parameter types after you changed type of property - i.e. you have to explicity change init declaration i.e. you must be sure that you want to change init method)

···

On 19.04.2016 0:51, Haravikk via swift-evolution wrote:

I agree with the intent of this, but perhaps not the solution; sticking
with the original example, simply being able to have an implied initialiser
for classes, as we have for structs, would be enough, for example:

    class Foo {
    let foo:String
    let bar:String
    let baz:Int

    var barCount:Int { return self.bar.characters.count } // Computed
    property, could be lazy instead I think?

    // Implied init(foo:String, bar:String, baz:Int)
    }

Personally I’m not a fan of the syntax, I wonder if an #autoinit or such
directive could be used to indicate properties that should be initialised
automatically where possible, like so:

    class Foo {
    #autoInit let foo:String
    #autoInit let bar:String
    #autoInit let baz:Int
    let barCount:Int

    init(foo:String, bar:String, baz:Int) {
    // foo, bar, baz handled behind the scenes
    self.barCount = bar.characters.count
    }

(or it could be on the parameters of the init function, might be clearer
that way)

Just an idea anyway

On 16 Apr 2016, at 14:17, Jonathan Hull via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Since we know the types of the properties, how about we replace the type
in the signature with either an indication that the property should be
automatically set, or better yet, the property which should be set:

class Foo
{
let foo : String
let bar : String
let barCount : Int
let baz : Int

init(foo: self.foo, bar: self.bar, baz: self.baz)
{
self.barCount = bar.characters.count
}

That way you don’t always have to have the init’s parameter names match
the names of the properties they set (even though they often would). We
could also allow a leading dot as a shorthand for ‘self.’

init(foo: .foo, bar: .bar, baz: .baz)

I think I like explicit ‘self.’ better, but that may just be my
preference. In either case, the generated interface would show the
actual type.

// init(foo: String, bar: String, baz: Int)

Thanks,
Jon

This is a common pattern for initialisers at the moment:

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(foo: String, bar: String, baz: Int)

{

self.foo = foo

self.bar = bar

self.baz = baz

barCount = bar.characters.count

}

}

This involves a lot of using 'self.'. For those who prefer not to use
'self.' explicitly everywhere, this is probably the main place it gets
used. It's a lot of boilerplate code.

How would it be if, like default variables, we could pack some of that
information into the argument tuple, and unify parameters with properties
immediately?

class Foo

{

let foo : String

let bar : String

let barCount : Int

let baz : Int

init(self.foo: String, self.bar: String, self.baz: Int)

{

barCount = bar.characters.count

}

}

Less boilerplate, more focus on the properties which need to be generated.

Thoughts?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution