[Pitch] Add the DefaultConstructible protocol to the standard library


(Braeden Profile) #1

I’m gonna do my best to explain my thoughts on this, as I just spent an hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library (especially under that name). It doesn’t explain its semantics effectively. I agree that a protocol should have definite semantics that are hopefully explained by the name. This protocol fails that test—a default instance of value types is completely context-specific, and default class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your own project and apply it to the types you think semantically fit the purpose…
  protocol ZeroConstructible { init() }
  extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too many definitions of “default”. What if I wanted Int to conform to multiple? It only can have one init(). I’d do something like this…
  protocol ZeroConstructible { static func constructZero() }
  protocol UnsafeConstructible { static func constructUnsafe() }
  protocol FactoryConstructible { static func constructDefault() } // I’ve never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s cumbersome, but correct. As of yet, I’ve never needed to do such a thing, and nearly all the use-cases brought up in the thread can be solved with something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

I read a new name suggested for the protocol: “Identity”. Unfortunately, I associate that with the proposed protocol HasIdentity { func === }, not a mathematical identity.
DefaultConstructible could never be a normal protocol that magically gets applied where init() exists. protocol required inits are just that—`required`. If a superclass conforms to DefaultConstructible, every subclass must, too! This would give most every class tree the infinite chain of `init()` that NSObject suffers from.
AnyObject was used to justify compiler magic that could be applied for DefaultConstructible. I disagree that this is appropriate, as AnyObject most certainly implies semantics. Every AnyObject is a class, with reference semantics, unsafe-weak-strong references, and more. I could not see definite semantics evolve for DefaultConstructible throughout the whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except those who try to understand this protocol, but I want to avoid that chaos.


(Daniel Leping) #2

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

···

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

swift-evolution@swift.org

https://lists.swift.org/mailman/listinfo/swift-evolution


(Tony Allevato) #3

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

···

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < swift-evolution@swift.org> wrote:

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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


(Daniel Leping) #4

Tony, could you, please, share your approaches? Maybe it will open the door
to finding an easy solution to the issue.

···

On Tue, 27 Dec 2016 at 10:02 Tony Allevato <tony.allevato@gmail.com> wrote:

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < > swift-evolution@swift.org> wrote:

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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


(Tony Allevato) #5

Tony, could you, please, share your approaches? Maybe it will open the
door to finding an easy solution to the issue.

...and I'll tell you what it is since I fat-fingered the send button too
soon. :slight_smile:

There have been a couple times where I've written code that needed to
generically serve instances of a type T, and in each of those cases—thanks
to Swift's support for first-class functions and
initializers-as-functions—I found it to be cleaner to have my factory take
a () -> T as a parameter and I pass T.init into that, rather than place
constraints on T itself.

This approach doesn't require imposing *any* additional constraints on T.
Even though it's trivial to use an extension to add conformance like
DefaultConstructible to many existing types, the latter approach excludes
any type that does not make sense to have a default initializer, or where
the default initializer isn't what you want to use. Maybe you want to have
your factory use a static method to create the objects of a certain type
instead: passing the function reference lets you do that. The function can
even be a closure that captures outer context, letting your factory work
for types that need additional parameters passed to the creation method.

In general, I think talking about factories as "a thing that needs to call
a specific initializer on a type" is a discussion motivated by patterns in
other languages that are more restrictive than Swift. If you think of a
factory instead as "something you can call that returns a T", the
functional approach is *much* more powerful and general.

···

On Mon, Dec 26, 2016 at 8:35 PM Daniel Leping <daniel@crossroadlabs.xyz> wrote:

On Tue, 27 Dec 2016 at 10:02 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < > swift-evolution@swift.org> wrote:

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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


Empty initializer protocol
Empty initializer protocol
(Daniel Leping) #6

Tony,

totally agree. The functional approach is great and it definitely is worth
being a default way of thinking in Swift.

From the API perspectives, though, it would still be good to have an

overload that accepts a type. Consider it library's syntactic sugar, but
still.

Moreover, functional approach is usually quite some complicated for newbies
which is not good for the library to be widely used.

In general I don't think we should be limited in Swift to be _functional
only_.

···

On Tue, 27 Dec 2016 at 10:09 Tony Allevato <tony.allevato@gmail.com> wrote:

On Mon, Dec 26, 2016 at 8:35 PM Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Tony, could you, please, share your approaches? Maybe it will open the
door to finding an easy solution to the issue.

...and I'll tell you what it is since I fat-fingered the send button too
soon. :slight_smile:

There have been a couple times where I've written code that needed to
generically serve instances of a type T, and in each of those cases—thanks
to Swift's support for first-class functions and
initializers-as-functions—I found it to be cleaner to have my factory take
a () -> T as a parameter and I pass T.init into that, rather than place
constraints on T itself.

This approach doesn't require imposing *any* additional constraints on T.
Even though it's trivial to use an extension to add conformance like
DefaultConstructible to many existing types, the latter approach excludes
any type that does not make sense to have a default initializer, or where
the default initializer isn't what you want to use. Maybe you want to have
your factory use a static method to create the objects of a certain type
instead: passing the function reference lets you do that. The function can
even be a closure that captures outer context, letting your factory work
for types that need additional parameters passed to the creation method.

In general, I think talking about factories as "a thing that needs to call
a specific initializer on a type" is a discussion motivated by patterns in
other languages that are more restrictive than Swift. If you think of a
factory instead as "something you can call that returns a T", the
functional approach is *much* more powerful and general.

On Tue, 27 Dec 2016 at 10:02 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < > swift-evolution@swift.org> wrote:

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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


(Xiaodi Wu) #7

With @autoclosure your user can simply write T() as an argument. It is very
elegant and not complicated at all.

···

On Mon, Dec 26, 2016 at 23:47 Daniel Leping via swift-evolution < swift-evolution@swift.org> wrote:

Tony,

totally agree. The functional approach is great and it definitely is worth
being a default way of thinking in Swift.

From the API perspectives, though, it would still be good to have an
overload that accepts a type. Consider it library's syntactic sugar, but
still.

Moreover, functional approach is usually quite some complicated for
newbies which is not good for the library to be widely used.

In general I don't think we should be limited in Swift to be _functional
only_.

On Tue, 27 Dec 2016 at 10:09 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:35 PM Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Tony, could you, please, share your approaches? Maybe it will open the
door to finding an easy solution to the issue.

...and I'll tell you what it is since I fat-fingered the send button too
soon. :slight_smile:

There have been a couple times where I've written code that needed to
generically serve instances of a type T, and in each of those cases—thanks
to Swift's support for first-class functions and
initializers-as-functions—I found it to be cleaner to have my factory take
a () -> T as a parameter and I pass T.init into that, rather than place
constraints on T itself.

This approach doesn't require imposing *any* additional constraints on T.
Even though it's trivial to use an extension to add conformance like
DefaultConstructible to many existing types, the latter approach excludes
any type that does not make sense to have a default initializer, or where
the default initializer isn't what you want to use. Maybe you want to have
your factory use a static method to create the objects of a certain type
instead: passing the function reference lets you do that. The function can
even be a closure that captures outer context, letting your factory work
for types that need additional parameters passed to the creation method.

In general, I think talking about factories as "a thing that needs to call
a specific initializer on a type" is a discussion motivated by patterns in
other languages that are more restrictive than Swift. If you think of a
factory instead as "something you can call that returns a T", the
functional approach is *much* more powerful and general.

On Tue, 27 Dec 2016 at 10:02 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < > swift-evolution@swift.org> wrote:

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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

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


(Tony Allevato) #8

Tony,

totally agree. The functional approach is great and it definitely is worth
being a default way of thinking in Swift.

From the API perspectives, though, it would still be good to have an
overload that accepts a type. Consider it library's syntactic sugar, but
still.

Moreover, functional approach is usually quite some complicated for
newbies which is not good for the library to be widely used.

Is asking a user to pass an initializer as an argument really more
complicated for a newcomer than requiring them to write an empty extension
to retroactively conform types they want to use with the factory to a new
protocol, though? I'd argue the opposite. Passing the initializer to the
factory makes the relationship between the two things very clear; relying
on a protocol constraint means that the conformance is applied far away
from the factory that requires it. In any case, neither retroactive
modeling nor initializers-as-functions is probably a "newbie" concept in
Swift so I would find it difficult to imagine that adoption of an API would
be harmed by choosing the latter.

···

On Mon, Dec 26, 2016 at 8:47 PM Daniel Leping <daniel@crossroadlabs.xyz> wrote:

In general I don't think we should be limited in Swift to be _functional
only_.

On Tue, 27 Dec 2016 at 10:09 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:35 PM Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Tony, could you, please, share your approaches? Maybe it will open the
door to finding an easy solution to the issue.

...and I'll tell you what it is since I fat-fingered the send button too
soon. :slight_smile:

There have been a couple times where I've written code that needed to
generically serve instances of a type T, and in each of those cases—thanks
to Swift's support for first-class functions and
initializers-as-functions—I found it to be cleaner to have my factory take
a () -> T as a parameter and I pass T.init into that, rather than place
constraints on T itself.

This approach doesn't require imposing *any* additional constraints on T.
Even though it's trivial to use an extension to add conformance like
DefaultConstructible to many existing types, the latter approach excludes
any type that does not make sense to have a default initializer, or where
the default initializer isn't what you want to use. Maybe you want to have
your factory use a static method to create the objects of a certain type
instead: passing the function reference lets you do that. The function can
even be a closure that captures outer context, letting your factory work
for types that need additional parameters passed to the creation method.

In general, I think talking about factories as "a thing that needs to call
a specific initializer on a type" is a discussion motivated by patterns in
other languages that are more restrictive than Swift. If you think of a
factory instead as "something you can call that returns a T", the
functional approach is *much* more powerful and general.

On Tue, 27 Dec 2016 at 10:02 Tony Allevato <tony.allevato@gmail.com> > wrote:

On Mon, Dec 26, 2016 at 8:31 PM Daniel Leping via swift-evolution < > swift-evolution@swift.org> wrote:

Braeden, a good point as for inheritance. Totally agree here.

Though the generic factory problem remains. Maybe it could be solved
differently? Any ideas?

As a matter of fact, I've used a different approach in some of my own
projects that has ended up working out well.

The only thing that pops up in mind right now is to have some "compiler
magic" that deals with the constraints. Maybe a concrete class can fall
into the category (be DefaultConstructable).

Anyways, my point is that compile time constraints for a type that can be
created with a default constructor are important for certain patterns. I'm
not saying the protocol is the right or the only way, but I want to find a
solution.

On Tue, 27 Dec 2016 at 5:22 Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

I’m gonna do my best to explain my thoughts on this, as I just spent an
hour reading the whole thread…………

I’m -1 on adding the protocol DefaultConstructible to the standard library
(especially under that name). It doesn’t explain its semantics
effectively. I agree that a protocol should have definite semantics that
are hopefully explained by the name. This protocol fails that test—a
default instance of value types is completely context-specific, and default
class instances are just iffy to me.

I’m firmly in the camp that you could create a protocol like this for your
own project and apply it to the types you think semantically fit the
purpose…
protocol ZeroConstructible { init() }
extension Int: ZeroConstructible { }
…but I wouldn’t do this myself, as there are too many use-cases with too
many definitions of “default”. What if I wanted Int to conform to
multiple? It only can have one init(). I’d do something like this…
protocol ZeroConstructible { static func constructZero() }
protocol UnsafeConstructible { static func constructUnsafe() }
protocol FactoryConstructible { static func constructDefault() } // I’ve
never needed to use a factory, myself...
…and create those new functions when I conform my types to it. It’s
cumbersome, but correct. As of yet, I’ve never needed to do such a thing,
and nearly all the use-cases brought up in the thread can be solved with
something of the like.

Every “default" is context-dependant.

Addressing other parts of the thread:

   - I read a new name suggested for the protocol: “Identity”.
   Unfortunately, I associate that with the proposed protocol HasIdentity {
   func === }, not a mathematical identity.
   - DefaultConstructible could never be a normal protocol that magically
   gets applied where init() exists. protocol required inits are just
   that—`required`. If a superclass conforms to DefaultConstructible, every
   subclass must, too! This would give most every class tree the infinite
   chain of `init()` that NSObject suffers from.
   - AnyObject was used to justify compiler magic that could be applied
   for DefaultConstructible. I disagree that this is appropriate, as
   AnyObject most certainly implies semantics. Every AnyObject is a class,
   with reference semantics, unsafe-weak-strong references, and more. I could
   not see definite semantics evolve for DefaultConstructible throughout the
   whole discussion.

That’s my two cents. Granted, no one would be hurt by its addition except
those who try to understand this protocol, but I want to avoid that chaos.

_______________________________________________

swift-evolution mailing list

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


(Braeden Profile) #9

I forgot to reply to the email list here.

···

On Dec 26, 2016, at 10:03 PM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

Did you mean to reply offlist?

Basically, a factory would be:

func make<T>(_: T.Type) -> T { return T() }

but you need T to conform to a protocol that guarantees T.init(). You use it like:

make(Foo.self)

But one can write:

func make<T>(_ f: @autoclosure () -> T) -> T { return f() }

and use this like:

make(Foo())

(pardon typos; freehanding on iPad)

On Mon, Dec 26, 2016 at 23:58 Braeden Profile <jhaezhyr12@gmail.com <mailto:jhaezhyr12@gmail.com>> wrote:
Actually, I’m a little lost at this point of exactly how you could build a function with this pattern. Code, anyone?

On Dec 26, 2016, at 9:57 PM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

With @autoclosure your user can simply write T() as an argument. It is very elegant and not complicated at all.


(Daniel Leping) #10

Actually T() would definitely do the job. Thanks for pointing. A can agree
it's a good replacement.

As for requiring to conform to a protocol - definitely worse solution. I
was thinking of DefaultConstructable as of automatically applied protocol
to anything that has init().

About "Zero" or "Identity" concept I personally tend to think of it as of a
singleton static property. Also keeping in mind everything said above in
the discussion these two are just different protocols. I.e. for Int "zero"
could be 0 and "identity" could be 1. Identity does not feel to be the
right name, though.

Also, for the "zeroable" types I would rather use nil.

···

On Tue, 27 Dec 2016 at 10:40 Braeden Profile via swift-evolution < swift-evolution@swift.org> wrote:

I forgot to reply to the email list here.

On Dec 26, 2016, at 10:03 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Did you mean to reply offlist?

Basically, a factory would be:

func make<T>(_: T.Type) -> T { return T() }

but you need T to conform to a protocol that guarantees T.init(). You use
it like:

make(Foo.self)

But one can write:

func make<T>(_ f: @autoclosure () -> T) -> T { return f() }

and use this like:

make(Foo())

(pardon typos; freehanding on iPad)

On Mon, Dec 26, 2016 at 23:58 Braeden Profile <jhaezhyr12@gmail.com> > wrote:

Actually, I’m a little lost at this point of exactly how you could build a
function with this pattern. Code, anyone?

On Dec 26, 2016, at 9:57 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

With @autoclosure your user can simply write T() as an argument. It is
very elegant and not complicated at all.

_______________________________________________

swift-evolution mailing list

swift-evolution@swift.org

https://lists.swift.org/mailman/listinfo/swift-evolution