[Pitch] Add the DefaultConstructible protocol to the standard library

I’ve never seen anyone use the empty init for it before, and if I ever will, I’ll probably discourage it. What is it for, anyways? Isn’t `Int.allZeros` enough?

···

On 26 Dec 2016, at 18:09, David Sweeris <davesweeris@mac.com> wrote:

On Dec 26, 2016, at 09:01, Tim Vermeulen via swift-evolution <swift-evolution@swift.org> wrote:

Then why is Int() allowed, and why does that return 0?

Predictability, I'd guess. The memory has to be initialized to *something*. And, IIRC, some architectures can 0 out memory faster than filling it with some other pattern.

- Dave Sweeris

Correct. Treating protocols as "bags of syntax" is tempting (I still find myself accidentally doing it from time to time), but that's not what a Swift protocol is.

Perhaps adding syntax to express a "bag of syntax" could be discussed either as its own topic (probably phase 2, but that's not my call), or later on as part of the macro system (it does sound rather macroish, IMHO).

- Dave Sweeris

···

On Dec 28, 2016, at 14:24, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Dec 28, 2016 at 5:21 PM, Anton Zhilin <antonyzhilin@gmail.com> wrote:
What about “Rust way”?

protocol Default {
    static var `default`: Self { get }
}

protocol Setupable {
    mutable func setup(with params: Params)
}

func setupArray<T>(type: T.Type, params: Params) -> [T]
    where T: Default & Setupable
{
    return (1...42).map { i in
        var next = T.default
        next.setup(with: params)
        return next
    }
}
default is literally a “default” value. For primitives like Int, Char, Bool, Float etc. it is all zeros. For structs with Default fields, it’s all defaults—unless some special semantics is given to them. For complex types, it’s an “empty” value, the most sane value before any setup or specification.

The objection is not about the spelling. The point here is that such a protocol does not make sufficient semantic guarantees to enable any interesting generic algorithms not possible without it. As I pointed out, Rust explicitly makes no guarantees as to what the default value is and tells you that you must not care; "most sane" does not cut it as a guarantee.

What about “Rust way”?

protocol Default {
    static var `default`: Self { get }
}

protocol Setupable {
    mutable func setup(with params: Params)
}

func setupArray<T>(type: T.Type, params: Params) -> [T]
    where T: Default & Setupable
{
    return (1...42).map { i in
        var next = T.default
        next.setup(with: params)
        return next
    }
}

default is literally a “default” value. For primitives like Int, Char,
Bool, Float etc. it is all zeros. For structs with Default fields, it’s
all defaults—unless some special semantics is given to them. For complex
types, it’s an “empty” value, the most sane value before any setup or
specification.

The objection is not about the spelling. The point here is that such a
protocol does not make sufficient semantic guarantees to enable any
interesting generic algorithms not possible without it. As I pointed out,
Rust explicitly makes no guarantees as to what the default value is and
tells you that you must not care; "most sane" does not cut it as a
guarantee.

···

On Wed, Dec 28, 2016 at 5:21 PM, Anton Zhilin <antonyzhilin@gmail.com> wrote:

Right.

Anton, perhaps I missed it, but I haven’t seen any concrete rationale for your proposal. Can you give some specific code examples that become simpler with a default constructible protocol? Perhaps you’re getting pushback because there is a better way to solve the problem you’re facing.

-Chris

···

On Dec 28, 2016, at 2:24 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Dec 28, 2016 at 5:21 PM, Anton Zhilin <antonyzhilin@gmail.com <mailto:antonyzhilin@gmail.com>> wrote:
What about “Rust way”?

protocol Default {
    static var `default`: Self { get }
}

protocol Setupable {
    mutable func setup(with params: Params)
}

func setupArray<T>(type: T.Type, params: Params) -> [T]
    where T: Default & Setupable
{
    return (1...42).map { i in
        var next = T.default
        next.setup(with: params)
        return next
    }
}
default is literally a “default” value. For primitives like Int, Char, Bool, Float etc. it is all zeros. For structs with Default fields, it’s all defaults—unless some special semantics is given to them. For complex types, it’s an “empty” value, the most sane value before any setup or specification.

The objection is not about the spelling. The point here is that such a protocol does not make sufficient semantic guarantees to enable any interesting generic algorithms not possible without it. As I pointed out, Rust explicitly makes no guarantees as to what the default value is and tells you that you must not care; "most sane" does not cut it as a guarantee.

Since people keep chiming in with “Rust has this”, I figured I should give the context for what’s up with Default in Rust. Disclaimer: I wasn’t around for the actual design of this API, but I worked with it a lot. So any justification I give is mostly my own posthoc perception of the purpose it serves today. I’ll also be using Swift terminology/syntax here since there’s no interesting aspect of Rust involved in this design.

There are three major use-cases for Default, as I see it:

1) providing conditional default initializers for generic types
2) providing a standard hook for easily writing “obvious” default initializers
3) refining another protocol for one-off convenience methods

The first case is easy. I have a `Mutex<T>`, `Box<T>`, `Rc<T>`, etc. Generic types which require an instance of their generic type to exist. So of course their initializer requires a T. But it would be nice to not have to do this for types which have default constructors. So you have `extension Mutex: Default where T: Default`, and now you can do `Mutex()` where inference makes it clear what the type is.

Here there’s no need to care about the “semantics” of Default. We’re just saying “if you can init() I can too!”.

The second case is fairly Rust-specific, in that it combines with other features to make default initialization more ergonomic. Default provides a custom deriver, which makes a super convenient way to write default constructors for Plain Old Data types. #[derive(Default)] just says “yeah add a default initializer that loads up every field with its default”. Often this is done on a concrete type full of integers/optionals, in which case it’s synonymous with zeroing.

Since initializers in Swift are totally first-class, one could conceivably create this kind of Derive system without the need for protocols. Although #[derive(Default)] is generics-aware, so it can provide conditional conformances for generic types too.

The third case is the most complex (and niche). In effect, there are several places where you can make a slightly more ergonomic thing if you refine a protocol with “has a default initializer”. These default initializers are in no sense a requirement of the protocol, so including the initializer as a requirement of the protocol is incorrect. At the same time, no one really wants a bunch of adhoc DefaultConstructibleX protocols that are used by maybe one or two functions in the entire world.

So Default is used as a universal modifier that can be applied to any protocol to create DefaultConstructibleX without anyone having to actually define or know about it. It’s a kind of retroactive modelling. If your type has some kind of reasonable default value, you conform to Default and maybe someone uses it. A particular user of `X + Default` then infers by example what a reasonable Default would mean in this context.

Examples in Rust:

* H: BuildHasher + Default — Default applies the BuildHasher’s default seeding algorithm. For some algorithms this will go out to /dev/urandom, for others this will just set it to 0. That’s the call of the BuildHasher’s designer, and is hopefully made clear in its docs. However, there’s no reason why default constructibility is fundamental to a hashing algorithm. One could reasonably make the call that there isn’t a good default, and require it to be manually constructed. Possibly they could provide a couple wrappers which provide a clear default (MySecureHasher, MyWeakHasher).

This constraint is used by HashMap<K, V, H> ’s default constructor. So in a sense this is just a more complex version of the first case, but we’re definitely inferring some semantics here. If a Default implementation doesn’t exist, then one must use HashMap’s with_hasher constructor to provide an instance of BuildHasher.

* R: Rng + Default — same basic idea. Default seeding strategy so you don’t have to pass an instance of Rng. No reason why all Rng’s must be default constructible.

* T: Extend + Default — if something can be Extended and provides a default constructor, then presumably it’s some kind of collection. So default is presumed to be the empty collection. Again, Extend is more primitive then collections — one of the ends of a channel reasonably implements Extend, but default construction doesn’t make sense in that context. This is used by

partition<C>(predicate: (Item) -> Bool) -> (C, C)
  where C: Extend + Default

which is basically just:

var yes = C()
var no = C()

for x in self {
  if predicate(x) {
    yes.extend(x)
  } else {
    no.extend(x)
  }
}

return (yes, no)

This is used similarly for unzip, which converts Iterator<(A, B)> to (CollectionOfA, CollectionOfB)

This case represents a situation where the Rust and Swift devs have diverged a bit philosophically. There’s a tendency in the Rust community to make small “lego” protocols which you snap together to get the semantics you want on the off chance there’s some weird type that doesn’t fit the mold. Swift tends to try to provide more fleshed out hierarchies.

This is partially influenced by the fact that fancy hierarchies are a lot easier to write and work with in Swift. Swift has much better support for retroactive modelling and crazy super-protocol-requirement-filling extensions. Defining things like Collection correctly in Rust has also generally been regarded as “needs some kind of higher kinded types” to handle the lifetime variables on Iterators.

All in all, I don’t really have an opinion on whether Default makes sense for Swift. Haven’t thought about it all that much. Swift is still missing the features that make case 1 and 2 even viable motivations (conditional conformance and derive annotations), and I believe already mandates default initializers in several of the cases where 3 is relevant.

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

···

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> wrote:

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> >> wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single
type in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the
value returned by a default initializer/constructor is regarded as an
identity element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of
types have a default value as is.

Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of
zero in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for
a new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should
be considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of
integers is a "more prominent and useful" operation than multiplication?
Again, this is backwards. Rather, we know that each numerical type belongs
to multiple ring algebras; there is no basis for reckoning any as "more
useful." Since `init()` can only ever give us one value at a time, we know
that `init()` cannot give a value that is a meaningful default with respect
to any particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide
a version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

On Sun, Dec 25, 2016 at 1:24 PM, Chris Lattner <clattner@apple.com> >> wrote:

On Dec 25, 2016, at 12:54 PM, Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

Does enabling a lot of small improvements that make APIs more ergonomic
count as practical?

Yes, that would count as practical, but Xiaodi’s question is just as
important. *Which* APIs become more ergonomic?

Here are a couple of more questions:

1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

2) To your original example, it isn’t immediately clear to me that reduce
should choose a default identity. Some types (e.g. integers and FP) belong
to multiple different ring algebras, and therefore have different identity
values that correspond to the relevant binary operations.

-Chris

On Sun, Dec 25, 2016 at 12:19 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 3:07 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

There's a book that provides quite a bit of info on this

https://smile.amazon.com/Elements-Programming-Alexander-Stepanov/dp/
032163537X?sa-no-redirect=1

They say that DefaultConstructible is one of the essential protocols on
which most algorithms rely in one way or another. One of the authors is the
designer of the C++ STL and basically the father of modern generics.

This protocol is important for any algebraic structure that deals with
the concept of appending or addition (as "zero" is one of the requirements
of monoid). There isn't a good short answer to your question. It's a
building block of algorithms. Think about why a RangeReplaceableCollection
can provide you with a default constructor but a Collection can't.

It's well and fine that most algorithms rely on the concept in one way or
another. Yet the Swift standard library already implements many generic
algorithms but has no DefaultConstructible, presumably because there are
other protocols that guarantee `init()` and the algorithms being
implemented don't need to be (practically speaking) generic over all
DefaultConstructible types. My question is: what practical use cases are
there for an explicit DefaultConstructible that are impractical today?

On Sun, Dec 25, 2016 at 11:37 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some other examples of generic algorithms that would make
use of this DefaultConstructible? I'm having trouble coming up with any
other than reduce.
On Sun, Dec 25, 2016 at 14:23 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

This protocol is present in C++ http://en.cppreference.com/w/cpp/concept/
DefaultConstructible as well as in Rust https://doc.rust-lang.org/std/
default/

It's the identity element/unit of a monoid or a zero.

The Swift implementation is very simple (I'm open to different names)

protocol DefaultConstructible {
    init()
}

A lot of the standard types could then be made to conform to this
protocol. These include all the numeric types, collection types (array,
set, dict), string, basically at least every type that currently has a
constructor without any arguments.

The RangeReplaceableCollection protocol would inherit from this protocol
as well.

This protocol would simplify a lot of generic algorithms where you need
the concept of a zero (which shows up a lot)

Once introduced, Sequence could define an alternative implementation of
reduce where the initial result doesn't need to be provided as it can be
default constructed.

_______________________________________________

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

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

In general I think the best showcase is generic factories.

···

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the value
returned by a default initializer/constructor is regarded as an identity
element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of types
have a default value as is.

Yes, those particular types have initializers that take no arguments. That
does not address my question. You merely restated your initial observation
that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of zero
in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for a
new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of integers
is a "more prominent and useful" operation than multiplication? Again, this
is backwards. Rather, we know that each numerical type belongs to multiple
ring algebras; there is no basis for reckoning any as "more useful." Since
`init()` can only ever give us one value at a time, we know that `init()`
cannot give a value that is a meaningful default with respect to any
particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

On Sun, Dec 25, 2016 at 1:24 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 25, 2016, at 12:54 PM, Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

Does enabling a lot of small improvements that make APIs more ergonomic
count as practical?

Yes, that would count as practical, but Xiaodi’s question is just as
important. *Which* APIs become more ergonomic?

Here are a couple of more questions:

1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

2) To your original example, it isn’t immediately clear to me that reduce
should choose a default identity. Some types (e.g. integers and FP) belong
to multiple different ring algebras, and therefore have different identity
values that correspond to the relevant binary operations.

-Chris

On Sun, Dec 25, 2016 at 12:19 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 3:07 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

There's a book that provides quite a bit of info on this

https://smile.amazon.com/Elements-Programming-Alexander-Stepanov/dp/032163537X?sa-no-redirect=1

They say that DefaultConstructible is one of the essential protocols on
which most algorithms rely in one way or another. One of the authors is the
designer of the C++ STL and basically the father of modern generics.

This protocol is important for any algebraic structure that deals with the
concept of appending or addition (as "zero" is one of the requirements of
monoid). There isn't a good short answer to your question. It's a building
block of algorithms. Think about why a RangeReplaceableCollection can
provide you with a default constructor but a Collection can't.

It's well and fine that most algorithms rely on the concept in one way or
another. Yet the Swift standard library already implements many generic
algorithms but has no DefaultConstructible, presumably because there are
other protocols that guarantee `init()` and the algorithms being
implemented don't need to be (practically speaking) generic over all
DefaultConstructible types. My question is: what practical use cases are
there for an explicit DefaultConstructible that are impractical today?

On Sun, Dec 25, 2016 at 11:37 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some other examples of generic algorithms that would make use
of this DefaultConstructible? I'm having trouble coming up with any other
than reduce.
On Sun, Dec 25, 2016 at 14:23 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

This protocol is present in C++
http://en.cppreference.com/w/cpp/concept/DefaultConstructible as well as
in Rust https://doc.rust-lang.org/std/default/

It's the identity element/unit of a monoid or a zero.

The Swift implementation is very simple (I'm open to different names)

protocol DefaultConstructible {
    init()
}

A lot of the standard types could then be made to conform to this
protocol. These include all the numeric types, collection types (array,
set, dict), string, basically at least every type that currently has a
constructor without any arguments.

The RangeReplaceableCollection protocol would inherit from this protocol
as well.

This protocol would simplify a lot of generic algorithms where you need
the concept of a zero (which shows up a lot)

Once introduced, Sequence could define an alternative implementation of
reduce where the initial result doesn't need to be provided as it can be
default constructed.

_______________________________________________

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

I’ve never seen anyone use the empty init for it before, and if I ever
will, I’ll probably discourage it. What is it for, anyways? Isn’t
`Int.allZeros` enough?

Well, that interface has to do with Int's role as a
BitwiseOperationsType, and is going away (see
https://github.com/apple/swift/pull/3796/commits/b9c910a2b94af461fc5de321cf12bf1cf45cb234)

···

on Mon Dec 26 2016, Tim Vermeulen <swift-evolution@swift.org> wrote:

On 26 Dec 2016, at 18:09, David Sweeris <davesweeris@mac.com> wrote:

On Dec 26, 2016, at 09:01, Tim Vermeulen via swift-evolution <swift-evolution@swift.org> wrote:

Then why is Int() allowed, and why does that return 0?

Predictability, I'd guess. The memory has to be initialized to
*something*. And, IIRC, some architectures can 0 out memory faster
than filling it with some other pattern.

- Dave Sweeris

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

--
-Dave

There's also Bool(), which gives you false. But if you look into the docs,
it tells you explicitly not to use Bool(). So, just to hazard a
guess--implementation artifact? After all, one can't prefix init with an
underscore.

···

On Mon, Dec 26, 2016 at 12:14 Tim Vermeulen via swift-evolution < swift-evolution@swift.org> wrote:

I’ve never seen anyone use the empty init for it before, and if I ever
will, I’ll probably discourage it. What is it for, anyways? Isn’t
`Int.allZeros` enough?

> On 26 Dec 2016, at 18:09, David Sweeris <davesweeris@mac.com> wrote:

>

>

>> On Dec 26, 2016, at 09:01, Tim Vermeulen via swift-evolution < > swift-evolution@swift.org> wrote:

>>

>> Then why is Int() allowed, and why does that return 0?

>

> Predictability, I'd guess. The memory has to be initialized to
*something*. And, IIRC, some architectures can 0 out memory faster than
filling it with some other pattern.

>

> - Dave Sweeris

_______________________________________________

swift-evolution mailing list

swift-evolution@swift.org

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

I *think* conditional conformance has already been accepted and just hasn’t been implemented yet, at least not in an official “can use to publish to app store” toolchain release.

- Dave Sweeris

···

On Jan 3, 2017, at 11:31 AM, Alexis via swift-evolution <swift-evolution@swift.org> wrote:

All in all, I don’t really have an opinion on whether Default makes sense for Swift. Haven’t thought about it all that much. Swift is still missing the features that make case 1 and 2 even viable motivations (conditional conformance and derive annotations), and I believe already mandates default initializers in several of the cases where 3 is relevant.

It's not, as far as I'm aware, working on master.

In any case, though, Box(T()) would be just as ergonomic as Box<T>() in
Swift, which I don't think is the case in Rust, and the former is already
possible without the need for conditional conformances.

···

On Tue, Jan 3, 2017 at 16:57 David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

> On Jan 3, 2017, at 11:31 AM, Alexis via swift-evolution < > swift-evolution@swift.org> wrote:
>
> All in all, I don’t really have an opinion on whether Default makes
sense for Swift. Haven’t thought about it all that much. Swift is still
missing the features that make case 1 and 2 even viable motivations
(conditional conformance and derive annotations), and I believe already
mandates default initializers in several of the cases where 3 is relevant.
I *think* conditional conformance has already been accepted and just
hasn’t been implemented yet, at least not in an official “can use to
publish to app store” toolchain release.

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

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

···

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz> wrote:

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz >> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> >> wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single
type in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the
value returned by a default initializer/constructor is regarded as an
identity element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of
types have a default value as is.

Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of
zero in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for
a new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should
be considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of
integers is a "more prominent and useful" operation than multiplication?
Again, this is backwards. Rather, we know that each numerical type belongs
to multiple ring algebras; there is no basis for reckoning any as "more
useful." Since `init()` can only ever give us one value at a time, we know
that `init()` cannot give a value that is a meaningful default with respect
to any particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide
a version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

On Sun, Dec 25, 2016 at 1:24 PM, Chris Lattner <clattner@apple.com> >> wrote:

On Dec 25, 2016, at 12:54 PM, Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

Does enabling a lot of small improvements that make APIs more ergonomic
count as practical?

Yes, that would count as practical, but Xiaodi’s question is just as
important. *Which* APIs become more ergonomic?

Here are a couple of more questions:

1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

2) To your original example, it isn’t immediately clear to me that reduce
should choose a default identity. Some types (e.g. integers and FP) belong
to multiple different ring algebras, and therefore have different identity
values that correspond to the relevant binary operations.

-Chris

On Sun, Dec 25, 2016 at 12:19 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 3:07 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

There's a book that provides quite a bit of info on this

https://smile.amazon.com/Elements-Programming-Alexander-Stepanov/dp/
032163537X?sa-no-redirect=1

They say that DefaultConstructible is one of the essential protocols on
which most algorithms rely in one way or another. One of the authors is the
designer of the C++ STL and basically the father of modern generics.

This protocol is important for any algebraic structure that deals with
the concept of appending or addition (as "zero" is one of the requirements
of monoid). There isn't a good short answer to your question. It's a
building block of algorithms. Think about why a RangeReplaceableCollection
can provide you with a default constructor but a Collection can't.

It's well and fine that most algorithms rely on the concept in one way or
another. Yet the Swift standard library already implements many generic
algorithms but has no DefaultConstructible, presumably because there are
other protocols that guarantee `init()` and the algorithms being
implemented don't need to be (practically speaking) generic over all
DefaultConstructible types. My question is: what practical use cases are
there for an explicit DefaultConstructible that are impractical today?

On Sun, Dec 25, 2016 at 11:37 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some other examples of generic algorithms that would make
use of this DefaultConstructible? I'm having trouble coming up with any
other than reduce.
On Sun, Dec 25, 2016 at 14:23 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

This protocol is present in C++ http://en.cppreference.com/w/cpp/concept/
DefaultConstructible as well as in Rust https://doc.rust-lang.org/std/
default/

It's the identity element/unit of a monoid or a zero.

The Swift implementation is very simple (I'm open to different names)

protocol DefaultConstructible {
    init()
}

A lot of the standard types could then be made to conform to this
protocol. These include all the numeric types, collection types (array,
set, dict), string, basically at least every type that currently has a
constructor without any arguments.

The RangeReplaceableCollection protocol would inherit from this protocol
as well.

This protocol would simplify a lot of generic algorithms where you need
the concept of a zero (which shows up a lot)

Once introduced, Sequence could define an alternative implementation of
reduce where the initial result doesn't need to be provided as it can be
default constructed.

_______________________________________________

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

You are right, usually it's required to implement a protocol which is not a
good approach. The best is plain objects which can be used independently of
ORM if needed (as DTOs, i.e.).

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for me.

···

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the value
returned by a default initializer/constructor is regarded as an identity
element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of types
have a default value as is.

Yes, those particular types have initializers that take no arguments. That
does not address my question. You merely restated your initial observation
that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of zero
in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for a
new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of integers
is a "more prominent and useful" operation than multiplication? Again, this
is backwards. Rather, we know that each numerical type belongs to multiple
ring algebras; there is no basis for reckoning any as "more useful." Since
`init()` can only ever give us one value at a time, we know that `init()`
cannot give a value that is a meaningful default with respect to any
particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

You are right, usually it's required to implement a protocol which is not a
good approach. The best is plain objects which can be used independently of
ORM if needed (as DTOs, i.e.).

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for
me.

Swift doesn't do implicit conformance. It always has to be declared
explicitly. I'm pretty sure Doug Gregor can explain why better than I
could.

···

on Sun Dec 25 2016, Daniel Leping <swift-evolution@swift.org> wrote:

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping >> <daniel@crossroadlabs.xyz> >> wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping >> <daniel@crossroadlabs.xyz> >> wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping >> <daniel@crossroadlabs.xyz> >> wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the value
returned by a default initializer/constructor is regarded as an identity
element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of types
have a default value as is.

Yes, those particular types have initializers that take no arguments. That
does not address my question. You merely restated your initial observation
that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of zero
in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for a
new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of integers
is a "more prominent and useful" operation than multiplication? Again, this
is backwards. Rather, we know that each numerical type belongs to multiple
ring algebras; there is no basis for reckoning any as "more useful." Since
`init()` can only ever give us one value at a time, we know that `init()`
cannot give a value that is a meaningful default with respect to any
particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

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

--
-Dave

Swift doesn't do implicit conformance. It always has to be declared

explicitly. I'm pretty sure Doug Gregor can explain why better than I
could.

I don't think Daniel was arguing for implicit conformance, he's saying that
if it makes sense for an object to have a default constructor, it makes
sense for it to conform to the protocol which I agree with 100%.

···

On Sun, Dec 25, 2016 at 9:17 PM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Sun Dec 25 2016, Daniel Leping <swift-evolution@swift.org> wrote:

> You are right, usually it's required to implement a protocol which is
not a
> good approach. The best is plain objects which can be used independently
of
> ORM if needed (as DTOs, i.e.).
>
> I was thinking of DefaultConstructable as a protocol automatically
applied
> to any class/struct having a default init, which is really logical for
> me.

Swift doesn't do implicit conformance. It always has to be declared
explicitly. I'm pretty sure Doug Gregor can explain why better than I
could.

> On Mon, 26 Dec 2016 at 9:41 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
>> On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping > >> <daniel@crossroadlabs.xyz> > >> wrote:
>>
>> Ok, an example from ORM. You have an entity factory with a virtual
(read,
>> overloadable in the subclasses) method populating the properties.
>> DefaultConstructable is a great choice here. Otherwise you will have to
>> force the users of your ORM to implement a certain protocol, which you
most
>> probably would like to avoid.
>>
>>
>> Sorry--I'm not very familiar with using Swift for ORM purposes. Why do
you
>> want to avoid having your users conform to a certain protocol? Wouldn't
the
>> users of your ORM have to conform to `DefaultConstructible` then? I'm
>> looking at Swift ORMs, and all require users to conform to a protocol or
>> inherit from a base class, typically named `Model` or similar. From a
quick
>> Google search:
>>
>> https://vapor.github.io/documentation/fluent/model.html
>> https://github.com/blitzagency/amigo-swift
>>
>>
>> In general I think the best showcase is generic factories.
>>
>> On Mon, 26 Dec 2016 at 9:02 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>>
>> On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping > >> <daniel@crossroadlabs.xyz> > >> wrote:
>>
>> Usually it's a generic function that needs to return a value from some
>> other function or a default value (zero) in a case of some conditions.
>> Optional value is an arguable solution in quite some scenarios. Afaik,
>> sometimes it can be used for optional resolution.
>>
>>
>> Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
>> there's not much you can do with a default value that you couldn't with
>> nil, unless you have some guarantee as to _what_ that default is;
however,
>> I'd expect that in every case that you can rely on a guarantee about a
>> default value which would be more useful than nil, it's going to require
>> more specific knowledge of your type than an all-encompassing
>> `DefaultConstructible` can provide.
>>
>> Also, generic factories. Widely used in ORM solutions.
>>
>>
>> Can you elaborate on this? Why is Optional not a solution here?
>>
>>
>> As mentioned above, algorythmical stuff that requires Zero.
>>
>>
>> I'm still not convinced there exist credible use cases that need to be
>> generic over both collections and floating point, for instance. In
fact, in
>> my experience, there are few math-heavy algorithms where one can ignore
>> even the distinction between integers and binary floating point. By the
>> time you get down to matrix math, you start to run into difficulties
that
>> require separate implementations for Float and Double.
>>
>> On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>>
>> Can you give some examples of what you used this approach to do?
>>
>>
>> On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping > >> <daniel@crossroadlabs.xyz> > >> wrote:
>>
>> +1 to this approach. I remember I had to create it on my own for my
>> projects. Would be nice to have it out of the box.
>>
>> On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > >> swift-evolution@swift.org> wrote:
>>
>> > Yes, those particular types have initializers that take no arguments.
>> That does not address my question. You merely restated your initial
>> observation that many types in Swift have implemented `init()`.
>>
>> Right, it's an empirical argument.
>>
>> > I didn't think the value returned by `init()` was regarded as any sort
>> of zero--or even any sort of "default." In fact, some types in
Foundation
>> have a static property called `default` distinct from `init()`.
>>
>> Let's not talk about those then. This would not apply to every single
type
>> in existence, as I've stated previously.
>>
>> > It gives you something different every time. How can this be squared
>> with your stated motivation regarding concepts of zero and concepts of
>> equality?
>>
>> Due to the fact that it's a resource, not a value. As I've stated above,
>> not all of this applies to types that are more resource-like.
>>
>> > Or, it's what you get because that's the most trivial possible string.
>> Quite simply, I do not think the designer of most types that implement
>> `init()` have paused to wonder whether the value that you get is the
>> identity element associated with the most useful and prominent operation
>> that can be performed on that type. I certainly never have.
>>
>> This is an appeal to tradition.
>>
>> > The statement I wrote was in JavaScript, so I'm not sure what you mean
>> by returning an optional. `[].reduce((a, b) => a + b)` results in an
>> error in JavaScript. In Swift, such a function may also be implemented
with
>> a precondition that the array is not empty and would not return an
optional.
>>
>> I was talking about their analogous swift implementations.
>>
>> > Can you give an example of an algorithm dealing with tensors where you
>> would use a `DefaultConstructible` generic over all types that have
>> `init()`, as opposed to working with the existing `Integer`,
>> `FloatingPoint`, and other numerical protocols?
>>
>> If it's implemented as either nested collections or numbers.
>>
>>
>>
>> On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>>
>> On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> > >> wrote:
>>
>> > Is it well settled, either in Swift or in C++/Rust/etc., that the
value
>> returned by a default initializer/constructor is regarded as an identity
>> element or zero?
>>
>> Int() == 0, String() == "" so to some extent by convention, a lot of
types
>> have a default value as is.
>>
>>
>> Yes, those particular types have initializers that take no arguments.
That
>> does not address my question. You merely restated your initial
observation
>> that many types in Swift have implemented `init()`.
>>
>> I didn't think the value returned by `init()` was regarded as any sort
of
>> zero--or even any sort of "default." In fact, some types in Foundation
have
>> a static property called `default` distinct from `init()`. In Rust, the
>> Default trait requires a function called `default()`, which is
documented
>> as being useful when you want "some kind of default value, and don't
>> particularly care what it is."
>>
>> I was asking whether there's some understanding, of which I've been
>> unaware, that the result of `init()` (or the equivalent in other
languages)
>> is expected to be some sort of zero or an identity element. I'm not
aware
>> of any evidence to that effect. Are you?
>>
>> > Is the thread that I get by writing `let t = Thread()` some kind of
zero
>> in any reasonable sense of the word?
>>
>> DefaultConstructibility makes less sense for types that represent some
>> sort of resource but make sense for things that are values. But even in
>> this case, Thread() gives you a default value for example if you are
>> working with a resizable collection of threads.
>>
>>
>> It gives you something different every time. How can this be squared
with
>> your stated motivation regarding concepts of zero and concepts of
equality?
>>
>> A better question is why does thread currently implement a default
>> constructor?
>>
>>
>> It's an initializer that takes no arguments, because none are needed
for a
>> new thread. How else would you write it?
>>
>> > Do you mean to argue that for an integer the additive identity should
be
>> considered "more prominent and useful" than the multiplicative identity?
>> I'm not aware of any mathematical justification for such a conclusion.
>>
>> I do. The justification is that if I call the default constructor of Int
>> currently, I get the value of 0.
>>
>>
>> This is backwards. Why do you believe that the value you obtain from
>> `init()` is intended to be an identity element at all, let alone the
most
>> important one? (It's also circular reasoning. Since `init()` only ever
>> gives you one value at a time, by your reasoning it demonstrates that
every
>> type must have one "more prominent and useful" identity, which is
begging
>> the question.)
>>
>> Which means that the binary operation must be addition.
>>
>>
>> Based on the value of `Int.init()`, you conclude that addition of
integers
>> is a "more prominent and useful" operation than multiplication? Again,
this
>> is backwards. Rather, we know that each numerical type belongs to
multiple
>> ring algebras; there is no basis for reckoning any as "more useful."
Since
>> `init()` can only ever give us one value at a time, we know that
`init()`
>> cannot give a value that is a meaningful default with respect to any
>> particular operation.
>>
>> If I call String() I get "" which is the identity of the + String
>> operation.
>>
>>
>> Or, it's what you get because that's the most trivial possible string.
>> Quite simply, I do not think the designer of most types that implement
>> `init()` have paused to wonder whether the value that you get is the
>> identity element associated with the most useful and prominent operation
>> that can be performed on that type. I certainly never have.
>>
>> > Going to your original example, I should add: other languages provide
a
>> version of `reduce` that doesn't require an initial result (for
instance,
>> JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
>> element at array index 0 as the initial result, and the accumulator
>> function is invoked starting with the element at array index 1. This is
>> precisely equivalent to having `reduce` use the additive identity as the
>> default initial result when + is the accumulator function and the
>> multiplicative identity when * is the accumulator function (with the
>> accumulator function being invoked starting with the element at array
index
>> 0). It does not require a DefaultConstructible protocol. What more
>> ergonomic solution could be implemented using a monoidic wrapper type?
>>
>> These two will have different signatures. The reduce you describe
returns
>> an optional,
>>
>>
>> The statement I wrote was in JavaScript, so I'm not sure what you mean
by
>> returning an optional. `[].reduce((a, b) => a + b)` results in an error
>> in JavaScript. In Swift, such a function may also be implemented with a
>> precondition that the array is not empty and would not return an
optional.
>>
>> the other one would returns the default value.
>>
>>
>> In what scenario would you prefer to propagate a default after reducing
a
>> potential empty collection _without supplying an explicit default_ for
that
>> operation? This would certainly violate the Swift convention of not
>> defaulting to zero and, I suspect, most users of Swift would not regard
>> that as ergonomic at all.
>>
>>
>> Fundamentally the default constructibles are useful in numerical
>> computations e..g. dealing with tensors.
>>
>>
>> Can you give an example of an algorithm dealing with tensors where you
>> would use a `DefaultConstructible` generic over all types that have
>> `init()`, as opposed to working with the existing `Integer`,
>> `FloatingPoint`, and other numerical protocols? (I should also add,
FWIW, I
>> have never seen a generic algorithm written for integers or FP types
that
>> has preferred the use of `T()` over `0`.)
>>
>>
>> On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>>
>> On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> > >> wrote:
>>
>> > *Which* APIs become more ergonomic?
>>
>> I'll get back to this question in a second if I may. This would be a
>> longer discussion and I first want to make sure that before we get into
the
>> details that there is a possibility of this being introduced (I'm
asking if
>> violating the no zero defaults is more important than slightly more
>> ergonomic APIs). But to give a broad answer I think that the concept of
a
>> zero is closely related to the concept of equality (and all the things
that
>> build up on equality such as comparability and negation).
>>
>> > 1) How does this square with Swift’s general philosophy to not default
>> initialize values to “zero”?
>>
>> I actually wasn't aware of this philosophy. Despite this philosophy,
look
>> at how many types actually currently implement a default constructor.
>>
>>
>> (Not a rhetorical question:) Is it well settled, either in Swift or in
>> C++/Rust/etc., that the value returned by a default
initializer/constructor
>> is regarded as an identity element or zero? Is the thread that I get by
>> writing `let t = Thread()` some kind of zero in any reasonable sense of
the
>> word?
>>
>>
>> Also can I ask what's the motivation behind this philosophy?
>> I think that in Swift, default constructibility makes complete sense for
>> (most?) structs, maybe less so for classes.
>>
>> > 2) To your original example, it isn’t immediately clear to me that
>> reduce should choose a default identity. Some types (e.g. integers and
FP)
>> belong to multiple different ring algebras, and therefore have different
>> identity values that correspond to the relevant binary operations.
>>
>> This is a good point that I've considered as well but felt that for the
>> most part, there is one particular identity and associated operation
that
>> is more prominent and useful than others. Furthermore, modeling
different
>> algebras isn't mutually exclusive with writing generic algorithms that
rely
>> on this protocol, you can always introduce some monoidic wrapper type
that
>> defines the more appropriate default value and operation.
>>
>>
>> Do you mean to argue that for an integer the additive identity should be
>> considered "more prominent and useful" than the multiplicative identity?
>> I'm not aware of any mathematical justification for such a conclusion.
>>
>> Going to your original example, I should add: other languages provide a
>> version of `reduce` that doesn't require an initial result (for
instance,
>> JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
>> element at array index 0 as the initial result, and the accumulator
>> function is invoked starting with the element at array index 1. This is
>> precisely equivalent to having `reduce` use the additive identity as the
>> default initial result when + is the accumulator function and the
>> multiplicative identity when * is the accumulator function (with the
>> accumulator function being invoked starting with the element at array
index
>> 0). It does not require a DefaultConstructible protocol. What more
>> ergonomic solution could be implemented using a monoidic wrapper type?
>>
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

--
-Dave

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

You are right, usually it's required to implement a protocol which is not
a good approach.

Why is it not?

The best is plain objects which can be used independently of ORM if needed
(as DTOs, i.e.).

An object that conforms to some protocol can still be used independently of
the ORM solution!

I was thinking of DefaultConstructable as a protocol automatically applied

···

On Sun, Dec 25, 2016 at 11:46 PM, Daniel Leping <daniel@crossroadlabs.xyz> wrote:

to any class/struct having a default init, which is really logical for me.

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz >> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do
you want to avoid having your users conform to a certain protocol? Wouldn't
the users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz >> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> >> wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single
type in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the
value returned by a default initializer/constructor is regarded as an
identity element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of
types have a default value as is.

Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of
zero in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for
a new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should
be considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of
integers is a "more prominent and useful" operation than multiplication?
Again, this is backwards. Rather, we know that each numerical type belongs
to multiple ring algebras; there is no basis for reckoning any as "more
useful." Since `init()` can only ever give us one value at a time, we know
that `init()` cannot give a value that is a meaningful default with respect
to any particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide
a version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

You are right, usually it's required to implement a protocol which is not
a good approach. The best is plain objects which can be used independently
of ORM if needed (as DTOs, i.e.).

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for me.

Again, protocols aren't about just syntax but about semantics. One
implication is that it's perfectly logical to have protocols with no syntax
requirements at all, i.e. `protocol MyProtocolWithSpecialSemantics { }`.
Another implication, therefore, is that Swift does not automatically
conform types to a protocol simply because it implements all requirements,
because there's no way for the compiler to judge semantics. If a protocol
can be automatically applied, it's a pretty good sign that it has no
semantic requirements and shouldn't be a protocol.

···

On Sun, Dec 25, 2016 at 11:46 PM, Daniel Leping <daniel@crossroadlabs.xyz> wrote:

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz >> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do
you want to avoid having your users conform to a certain protocol? Wouldn't
the users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz >> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> >> wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < >> swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single
type in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the
value returned by a default initializer/constructor is regarded as an
identity element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of
types have a default value as is.

Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of
zero in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for
a new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should
be considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of
integers is a "more prominent and useful" operation than multiplication?
Again, this is backwards. Rather, we know that each numerical type belongs
to multiple ring algebras; there is no basis for reckoning any as "more
useful." Since `init()` can only ever give us one value at a time, we know
that `init()` cannot give a value that is a meaningful default with respect
to any particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

> Going to your original example, I should add: other languages provide
a version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

These two will have different signatures. The reduce you describe returns
an optional,

The statement I wrote was in JavaScript, so I'm not sure what you mean by
returning an optional. `[].reduce((a, b) => a + b)` results in an error
in JavaScript. In Swift, such a function may also be implemented with a
precondition that the array is not empty and would not return an optional.

the other one would returns the default value.

In what scenario would you prefer to propagate a default after reducing a
potential empty collection _without supplying an explicit default_ for that
operation? This would certainly violate the Swift convention of not
defaulting to zero and, I suspect, most users of Swift would not regard
that as ergonomic at all.

Fundamentally the default constructibles are useful in numerical
computations e..g. dealing with tensors.

Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols? (I should also add, FWIW, I
have never seen a generic algorithm written for integers or FP types that
has preferred the use of `T()` over `0`.)

On Sun, Dec 25, 2016 at 3:30 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <adamnemecek@gmail.com> >> wrote:

> *Which* APIs become more ergonomic?

I'll get back to this question in a second if I may. This would be a
longer discussion and I first want to make sure that before we get into the
details that there is a possibility of this being introduced (I'm asking if
violating the no zero defaults is more important than slightly more
ergonomic APIs). But to give a broad answer I think that the concept of a
zero is closely related to the concept of equality (and all the things that
build up on equality such as comparability and negation).

> 1) How does this square with Swift’s general philosophy to not default
initialize values to “zero”?

I actually wasn't aware of this philosophy. Despite this philosophy, look
at how many types actually currently implement a default constructor.

(Not a rhetorical question:) Is it well settled, either in Swift or in
C++/Rust/etc., that the value returned by a default initializer/constructor
is regarded as an identity element or zero? Is the thread that I get by
writing `let t = Thread()` some kind of zero in any reasonable sense of the
word?

Also can I ask what's the motivation behind this philosophy?
I think that in Swift, default constructibility makes complete sense for
(most?) structs, maybe less so for classes.

> 2) To your original example, it isn’t immediately clear to me that
reduce should choose a default identity. Some types (e.g. integers and FP)
belong to multiple different ring algebras, and therefore have different
identity values that correspond to the relevant binary operations.

This is a good point that I've considered as well but felt that for the
most part, there is one particular identity and associated operation that
is more prominent and useful than others. Furthermore, modeling different
algebras isn't mutually exclusive with writing generic algorithms that rely
on this protocol, you can always introduce some monoidic wrapper type that
defines the more appropriate default value and operation.

Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

Going to your original example, I should add: other languages provide a
version of `reduce` that doesn't require an initial result (for instance,
JavaScript). In JavaScript, `[1, 2, 3].reduce((a, b) => a + b)` uses the
element at array index 0 as the initial result, and the accumulator
function is invoked starting with the element at array index 1. This is
precisely equivalent to having `reduce` use the additive identity as the
default initial result when + is the accumulator function and the
multiplicative identity when * is the accumulator function (with the
accumulator function being invoked starting with the element at array index
0). It does not require a DefaultConstructible protocol. What more
ergonomic solution could be implemented using a monoidic wrapper type?

Ok, which approach is easier? Plain struct working out of the box or adding
an additional conformance? I like the usage be as easy as possible and as
less effort as possible.

···

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

On Sun, Dec 25, 2016 at 11:46 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

You are right, usually it's required to implement a protocol which is not
a good approach.

Why is it not?

The best is plain objects which can be used independently of ORM if needed
(as DTOs, i.e.).

An object that conforms to some protocol can still be used independently
of the ORM solution!

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for me.

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the value
returned by a default initializer/constructor is regarded as an identity
element or zero?

Int() == 0, String() == "" so to some extent by convention, a lot of types
have a default value as is.

Yes, those particular types have initializers that take no arguments. That
does not address my question. You merely restated your initial observation
that many types in Swift have implemented `init()`.

I didn't think the value returned by `init()` was regarded as any sort of
zero--or even any sort of "default." In fact, some types in Foundation have
a static property called `default` distinct from `init()`. In Rust, the
Default trait requires a function called `default()`, which is documented
as being useful when you want "some kind of default value, and don't
particularly care what it is."

I was asking whether there's some understanding, of which I've been
unaware, that the result of `init()` (or the equivalent in other languages)
is expected to be some sort of zero or an identity element. I'm not aware
of any evidence to that effect. Are you?

> Is the thread that I get by writing `let t = Thread()` some kind of zero
in any reasonable sense of the word?

DefaultConstructibility makes less sense for types that represent some
sort of resource but make sense for things that are values. But even in
this case, Thread() gives you a default value for example if you are
working with a resizable collection of threads.

It gives you something different every time. How can this be squared with
your stated motivation regarding concepts of zero and concepts of equality?

A better question is why does thread currently implement a default
constructor?

It's an initializer that takes no arguments, because none are needed for a
new thread. How else would you write it?

> Do you mean to argue that for an integer the additive identity should be
considered "more prominent and useful" than the multiplicative identity?
I'm not aware of any mathematical justification for such a conclusion.

I do. The justification is that if I call the default constructor of Int
currently, I get the value of 0.

This is backwards. Why do you believe that the value you obtain from
`init()` is intended to be an identity element at all, let alone the most
important one? (It's also circular reasoning. Since `init()` only ever
gives you one value at a time, by your reasoning it demonstrates that every
type must have one "more prominent and useful" identity, which is begging
the question.)

Which means that the binary operation must be addition.

Based on the value of `Int.init()`, you conclude that addition of integers
is a "more prominent and useful" operation than multiplication? Again, this
is backwards. Rather, we know that each numerical type belongs to multiple
ring algebras; there is no basis for reckoning any as "more useful." Since
`init()` can only ever give us one value at a time, we know that `init()`
cannot give a value that is a meaningful default with respect to any
particular operation.

If I call String() I get "" which is the identity of the + String
operation.

Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is a very old discussion that took plays years ago with POJO vs
JavaBean approach. For sure, extensions give us a bit more flexibility,
though the subject remains the same.

Extensions are not a panacea and I think we should always look back for
good proven patterns rather than reinvent the wheel.

Also, consider SpringFramework-like solution in Swift. How would you deal
with object factories without DefaultConstructable in an elegant way? Also,
I have some plans to work on one soon, so I consider this topic quite some
important.

···

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

On Sun, Dec 25, 2016 at 11:52 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, which approach is easier? Plain struct working out of the box or
adding an additional conformance? I like the usage be as easy as possible
and as less effort as possible.

I'd say `class Foo { ... }` and `class Foo : Model { ... }` are equal in
ease and effort.

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

On Sun, Dec 25, 2016 at 11:46 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

You are right, usually it's required to implement a protocol which is not
a good approach.

Why is it not?

The best is plain objects which can be used independently of ORM if needed
(as DTOs, i.e.).

An object that conforms to some protocol can still be used independently
of the ORM solution!

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for me.

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

> It gives you something different every time. How can this be squared
with your stated motivation regarding concepts of zero and concepts of
equality?

Due to the fact that it's a resource, not a value. As I've stated above,
not all of this applies to types that are more resource-like.

> Or, it's what you get because that's the most trivial possible string.
Quite simply, I do not think the designer of most types that implement
`init()` have paused to wonder whether the value that you get is the
identity element associated with the most useful and prominent operation
that can be performed on that type. I certainly never have.

This is an appeal to tradition.

> The statement I wrote was in JavaScript, so I'm not sure what you mean
by returning an optional. `[].reduce((a, b) => a + b)` results in an
error in JavaScript. In Swift, such a function may also be implemented with
a precondition that the array is not empty and would not return an optional.

I was talking about their analogous swift implementations.

> Can you give an example of an algorithm dealing with tensors where you
would use a `DefaultConstructible` generic over all types that have
`init()`, as opposed to working with the existing `Integer`,
`FloatingPoint`, and other numerical protocols?

If it's implemented as either nested collections or numbers.

On Sun, Dec 25, 2016 at 6:00 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <adamnemecek@gmail.com> > wrote:

> Is it well settled, either in Swift or in C++/Rust/etc., that the value
returned by a default initializer/constructor is regarded as an identity
element or zero?

I'm not against explicit protocol conformance for custom stuff, but doesn't
default constructor look like a very common use case?

Again, I'm completely against implicit conformance for custom stuff, but
this one is of the same level as AnyObject implicit conformance. It's an
exception, isn't it? Why can't we do the same for DefaultConstructable
which is the case for most classes/structs?

As for the Spring-like DIs. I have some experience implementing such in C++
and yes, this feature is mandatory to get one in Swift without any use of
advanced reflection.

Seriously, I want to have a capability in generic functions to restrict
parameters to DefultConstructable and factories is an obvious use case.
Hope it's very clear why.

···

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

On Mon, Dec 26, 2016 at 12:05 AM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

This is a very old discussion that took plays years ago with POJO vs
JavaBean approach. For sure, extensions give us a bit more flexibility,
though the subject remains the same.

Extensions are not a panacea and I think we should always look back for
good proven patterns rather than reinvent the wheel.

Also, consider SpringFramework-like solution in Swift. How would you deal
with object factories without DefaultConstructable in an elegant way?

Without being extremely familiar with this area, I'd imagine it would
depend on more advanced reflection facilities in any case, which are a
topic for future versions of Swift. Moreover, in a language where immutable
value types are idiomatic, `init()` wouldn't help you there at all, and
you'll have to be working with code written in a very different way anyway.
So I guess I'm not sure why conforming to a protocol explicitly (and
retroactively, if necessary) is what's standing in the way of whatever
solution you're reaching for.

Also, I have some plans to work on one soon, so I consider this topic
quite some important.

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

On Sun, Dec 25, 2016 at 11:52 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, which approach is easier? Plain struct working out of the box or
adding an additional conformance? I like the usage be as easy as possible
and as less effort as possible.

I'd say `class Foo { ... }` and `class Foo : Model { ... }` are equal in
ease and effort.

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

On Sun, Dec 25, 2016 at 11:46 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

You are right, usually it's required to implement a protocol which is not
a good approach.

Why is it not?

The best is plain objects which can be used independently of ORM if needed
(as DTOs, i.e.).

An object that conforms to some protocol can still be used independently
of the ORM solution!

I was thinking of DefaultConstructable as a protocol automatically applied
to any class/struct having a default init, which is really logical for me.

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

On Sun, Dec 25, 2016 at 10:50 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Ok, an example from ORM. You have an entity factory with a virtual (read,
overloadable in the subclasses) method populating the properties.
DefaultConstructable is a great choice here. Otherwise you will have to
force the users of your ORM to implement a certain protocol, which you most
probably would like to avoid.

Sorry--I'm not very familiar with using Swift for ORM purposes. Why do you
want to avoid having your users conform to a certain protocol? Wouldn't the
users of your ORM have to conform to `DefaultConstructible` then? I'm
looking at Swift ORMs, and all require users to conform to a protocol or
inherit from a base class, typically named `Model` or similar. From a quick
Google search:

https://vapor.github.io/documentation/fluent/model.html
https://github.com/blitzagency/amigo-swift

In general I think the best showcase is generic factories.

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

On Sun, Dec 25, 2016 at 10:18 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

Usually it's a generic function that needs to return a value from some
other function or a default value (zero) in a case of some conditions.
Optional value is an arguable solution in quite some scenarios. Afaik,
sometimes it can be used for optional resolution.

Right, I'd agree that Optional is the idiomatic way to do it. Afaict,
there's not much you can do with a default value that you couldn't with
nil, unless you have some guarantee as to _what_ that default is; however,
I'd expect that in every case that you can rely on a guarantee about a
default value which would be more useful than nil, it's going to require
more specific knowledge of your type than an all-encompassing
`DefaultConstructible` can provide.

Also, generic factories. Widely used in ORM solutions.

Can you elaborate on this? Why is Optional not a solution here?

As mentioned above, algorythmical stuff that requires Zero.

I'm still not convinced there exist credible use cases that need to be
generic over both collections and floating point, for instance. In fact, in
my experience, there are few math-heavy algorithms where one can ignore
even the distinction between integers and binary floating point. By the
time you get down to matrix math, you start to run into difficulties that
require separate implementations for Float and Double.

On Mon, 26 Dec 2016 at 8:38 Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Can you give some examples of what you used this approach to do?

On Sun, Dec 25, 2016 at 9:49 PM, Daniel Leping <daniel@crossroadlabs.xyz> > wrote:

+1 to this approach. I remember I had to create it on my own for my
projects. Would be nice to have it out of the box.

On Mon, 26 Dec 2016 at 8:11 Adam Nemecek via swift-evolution < > swift-evolution@swift.org> wrote:

> Yes, those particular types have initializers that take no arguments.
That does not address my question. You merely restated your initial
observation that many types in Swift have implemented `init()`.

Right, it's an empirical argument.

> I didn't think the value returned by `init()` was regarded as any sort
of zero--or even any sort of "default." In fact, some types in Foundation
have a static property called `default` distinct from `init()`.

Let's not talk about those then. This would not apply to every single type
in existence, as I've stated previously.

Terms of Service

Privacy Policy

Cookie Policy