> 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 <[email protected]> wrote: > On Sun, Dec 25, 2016 at 7:30 PM, Adam Nemecek <[email protected]> > 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 <[email protected]> wrote: >> >>> On Sun, Dec 25, 2016 at 5:27 PM, Adam Nemecek <[email protected]> >>> 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 <[email protected]> >>>> wrote: >>>> >>>>> On Dec 25, 2016, at 12:54 PM, Adam Nemecek via swift-evolution < >>>>> [email protected]> 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 <[email protected]> >>>>> wrote: >>>>> >>>>>> On Sun, Dec 25, 2016 at 3:07 PM, Adam Nemecek <[email protected]> >>>>>> wrote: >>>>>> >>>>>>> There's a book that provides quite a bit of info on this >>>>>>> >>>>>>> https://smile.amazon.com/Elements-Programming-Alexander-Step >>>>>>> anov/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 <[email protected]> >>>>>>> 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 < >>>>>>>> [email protected]> 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 >>>>>>>>> [email protected] >>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> >>>>> >>>>> >>>> >>> >> >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
