January 21, 2019
On Thursday, 17 January 2019 at 23:34:17 UTC, H. S. Teoh wrote:
> At the very least, it would seem that the *name* of the type plays an essential role in its identification.  I.e., it's almost as if a struct declaration is actually defining a type that, in addition to the types of its fields, contains also an implicit string type identifying the name of the struct. Or alternatively, we're dealing with a type system where types are additionally decorated with string identifiers that distinguish otherwise-identical types from each other.

I wonder if there's a body of research in type theory about "decorated members" structural type systems; eg, where the name of an aggregate isn't part of its type, but the name of its members is.

For instance, in the following example:

    struct Point {
        float x;
        float y;
    }

    struct CartesianCoors {
        float x;
        float y;
    }

    struct PolarCoors {
        float theta;
        float radius;
    }

Point would be equivalent to CartesianCoors, but different from PolarCoors

> (Or it could be that I've no idea what I'm talking about, and this is the consequence of this community having very few people who actually know type theory thoroughly enough to be able to work out a sane solution to all of these issues. :-P)

Don't feel bad. Type theory communities aren't exactly great at designing sane solution usable by human beings either :P
January 21, 2019
On Mon, 21 Jan 2019 17:01:54 +0000, Olivier FAURE wrote:
> On Thursday, 17 January 2019 at 23:34:17 UTC, H. S. Teoh wrote:
>> At the very least, it would seem that the *name* of the type plays an essential role in its identification.  I.e., it's almost as if a struct declaration is actually defining a type that, in addition to the types of its fields, contains also an implicit string type identifying the name of the struct. Or alternatively, we're dealing with a type system where types are additionally decorated with string identifiers that distinguish otherwise-identical types from each other.
> 
> I wonder if there's a body of research in type theory about "decorated members" structural type systems; eg, where the name of an aggregate isn't part of its type, but the name of its members is.

That's what structural typing generally is. In essence, with structural typing, everything is a NamedTuple that implicitly casts to any projection of its fields.

The more extreme variant, where everything is a tuple that implicitly casts to any prefix of itself, is not very useful.
January 22, 2019
H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> On Thu, Jan 17, 2019 at 09:43:52PM +0000, Jonathan Marler via Digitalmars-d wrote:
>[...]
>> That's conceptually the same thing.  Saying that TBottom* is "always equal to null" is the same as saying it's a Unit Type, which is the same as saying that it contains no information so the storage needed is 0 (same as void).
> 
> I'm not so sure about that.  A true Unit type conveys no information, yet TBottom* conveys at least this information: that it's a pointer, and that the pointer cannot be dereferenced.  A true Unit type would be the return type of a void function; would you equate TBottom* with the return type of a void function?  That would be very strange indeed.

A unit type carrying no value means that the *dynamic value at runtime* carries no information that is not already known from the type itself.

Take 'bool' as an example. It carries only one bit of dynami information, yet from the type itself you also know that it's no 'int' or pointer type which is definitely more than one bit of information. But it's the dynamic information that counts.

If you have a variable (or return value) of type 'TBottom*' you already know from the type that the value will be 'null'. In other words there is no need to use any storage for that value.

Tobi

January 22, 2019
H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> I don't argue that it's not a unit type.  But that's not the same thing as saying it's *the* unit type.  There may be multiple, distinct unit types, because D types are not structural types in the type theoretic sense;

Since a unit type consists of a single value, there exist as much unit types as there exist values (at least in theory). The type that only has the value '123' is a unit type as well as the type with the single value 'true' or an empty struct or tuple.

Which one serves as 'canonical' unit type is merely convention.

OTOH there can only be a single top type and a single bottom type by definition.

---
Tobi
January 22, 2019
On Tue, 22 Jan 2019 06:29:41 +0000, Tobias Müller wrote:
> Take 'bool' as an example. It carries only one bit of dynami information, yet from the type itself you also know that it's no 'int' or pointer type which is definitely more than one bit of information.

Point of pedantry: bool is an integer type according to the type specialization rules, a more specific subtype of 'int'. It can participate in some arithmetic expressions, though it omits things like ++ and +=.

So you can write things like:

    i = i + true | ((true + true) ^^ (true + true + true) ^ false);

And this code uses the bool overload:

    void foo(bool b) { writeln("bool"); }
    void foo(short b) { writeln("ubyte"); }
    foo(cast(ubyte)0);

I'm not sure anyone but Walter thinks this is a good idea.
January 22, 2019
On Tuesday, 22 January 2019 at 06:57:24 UTC, Neia Neutuladh wrote:
> Point of pedantry: bool is an integer type according to the type specialization rules, a more specific subtype of 'int'. It can participate in some arithmetic expressions, though it omits things like ++ and +=.
>
> So you can write things like:
>
>     i = i + true | ((true + true) ^^ (true + true + true) ^ false);
>
> And this code uses the bool overload:
>
>     void foo(bool b) { writeln("bool"); }
>     void foo(short b) { writeln("ubyte"); }
>     foo(cast(ubyte)0);
>
> I'm not sure anyone but Walter thinks this is a good idea.

Indeed, hopefully we can convince Andrei to reverse the decision on DIP1015 at dconf.
January 22, 2019
On Monday, 21 January 2019 at 17:52:52 UTC, Neia Neutuladh wrote:
> That's what structural typing generally is. In essence, with structural typing, everything is a NamedTuple that implicitly casts to any projection of its fields.

I'm not sure. Most discussions I've seen equate structural typing with structures being tuples with no naming, and using field names to differentiate types with nominal typing.

I haven't seen much discussion of the difference between "structural with names" type systems (structs are NamedTuples) and "pure structural" type systems (structs are tuples).

> The more extreme variant, where everything is a tuple that implicitly casts to any prefix of itself, is not very useful.

Why?

Everything you can do with nominal typing, you can do with named structural typing.
January 22, 2019
On Tuesday, 22 January 2019 at 10:23:09 UTC, Nicholas Wilson wrote:
> On Tuesday, 22 January 2019 at 06:57:24 UTC, Neia Neutuladh wrote:
>> Point of pedantry: bool is an integer type according to the type specialization rules, a more specific subtype of 'int'. It can participate in some arithmetic expressions, though it omits things like ++ and +=.
>>
>> So you can write things like:
>>
>>     i = i + true | ((true + true) ^^ (true + true + true) ^ false);
>>
>> And this code uses the bool overload:
>>
>>     void foo(bool b) { writeln("bool"); }
>>     void foo(short b) { writeln("ubyte"); }
>>     foo(cast(ubyte)0);
>>
>> I'm not sure anyone but Walter thinks this is a good idea.
>
> Indeed, hopefully we can convince Andrei to reverse the decision on DIP1015 at dconf.

Good luck with that, you going to need it.
January 22, 2019
On Tuesday, 22 January 2019 at 06:57:24 UTC, Neia Neutuladh wrote:
> On Tue, 22 Jan 2019 06:29:41 +0000, Tobias Müller wrote:
>> [...]
>
> Point of pedantry: bool is an integer type according to the type specialization rules, a more specific subtype of 'int'. It can participate in some arithmetic expressions, though it omits things like ++ and +=.
>
> So you can write things like:
>
>     i = i + true | ((true + true) ^^ (true + true + true) ^ false);
>
> And this code uses the bool overload:
>
>     void foo(bool b) { writeln("bool"); }
>     void foo(short b) { writeln("ubyte"); }
>     foo(cast(ubyte)0);
>
> I'm not sure anyone but Walter thinks this is a good idea.

I'm still salty about DIP1015
January 22, 2019
On Tue, 22 Jan 2019 12:57:10 +0000, Olivier FAURE wrote:
> On Monday, 21 January 2019 at 17:52:52 UTC, Neia Neutuladh wrote:
>> The more extreme variant, where everything is a tuple that implicitly casts to any prefix of itself, is not very useful.
> 
> Why?

Because it makes field order significant. It means that these two types are different:

    struct A { int x; string y; }
    struct B { string y; int x; }

The first is Tuple!(int, string); the second is Tuple!(string, int). They look like they should convert to each other, but they don't.

And these two types *do* convert to each other, but not in the way you'd want:

    struct A { bool destroyEarth; bool preserveHumanity; }
    struct B { bool preserveHumanity; bool destroyEarth; }

Passing the wrong type flips the fields around, because the order of the fields is what matters, because that's part of the structure. And that's why nobody actually suggests this.