November 29, 2021

On Monday, 29 November 2021 at 11:34:41 UTC, bauss wrote:

>

Pretty much anything can be solved in a library, except for things that requires AST/macros.

There is no way to implicitly convert from other types (particularly built-in types) to a struct, and I think Walter is opposed to introducing that. This means no null -> Slice or null -> AA and other implicit conversions. So any library solution would be more awkward to use compared to the current language equivalents.

November 29, 2021

On Monday, 29 November 2021 at 12:30:42 UTC, user1234 wrote:

>

static casts, devirtualization, are reasons for built-in classes.

Casting is a weakness in D (in comparison to C++) so that is an area that needs improvement.

I am not sure if devirtualization is a good argument, as you should be able to have immutable pointers and "devirtualize" those in general.

Also, since it would be a standard library construct a good compiler could have a special path for those. So it should remain the same.

>

Things for classes that can be done in the library are already done there, e.g dynamic casts.

I am not so sure. If we give structs inheritance and some other minor adjustments then I think class could be done as a library construct just as well as the current builtin.

November 29, 2021

On Monday, 29 November 2021 at 12:51:47 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 29 November 2021 at 12:30:42 UTC, user1234 wrote:

>

static casts, devirtualization, are reasons for built-in
Also, since it would be a standard library construct a good compiler could have a special path for those. So it should remain the same.

If there must be a special path then it's already a failed library solution, not to say a lie. You make think to the user that classes is a library thing but it's not.

November 29, 2021

On Monday, 29 November 2021 at 12:47:35 UTC, Nick Treleaven wrote:

>

On Monday, 29 November 2021 at 11:34:41 UTC, bauss wrote:

>

Pretty much anything can be solved in a library, except for things that requires AST/macros.

There is no way to implicitly convert from other types (particularly built-in types) to a struct, and I think Walter is opposed to introducing that. This means no null -> Slice or null -> AA and other implicit conversions.

But isn't a slice basically a struct with pointer and length?
Therefore you can consider that a slice is never null, but rather internal ptr field is, while length is 0.
The assoc array could follow same logic, i.e. point to null node.

any ops could then be implemented in terms of operator overloading.

I mean, the purpose of operator overloading was added to allow user types to simulate built in ones, but what if this is inverted?
i.e. have the slices, arrays and aas, be implemented using structs with operator overloading for defining their behavior. This imho should make the compiler code and arch more decoupled and easy to manage compared to current situation. i.e. you won't need all tightly coupled magic hook for aas, arrays, etc. and could focus on improving operator overloading to support built in types behavior (not talking about classes here).

November 29, 2021

On Monday, 29 November 2021 at 11:34:41 UTC, bauss wrote:

>

Pretty much anything can be solved in a library, except for things that requires AST/macros.

I think we can assume that the AST closely matches the core language since we assume «D3». So I think we also can assume the ability to at least construct AST trees programatically (maybe also inspect, but I don't fully understand the implications in relation to static if etc).

This would allow for more elegant and less error-prone creation of facades and interfacing-types (e.g. automatic construction of intelligent smart pointers, APIs for transport over network etc.)

November 29, 2021

On Monday, 29 November 2021 at 13:11:47 UTC, Alexandru Ermicioi wrote:

>

But isn't a slice basically a struct with pointer and length?
Therefore you can consider that a slice is never null, but rather internal ptr field is, while length is 0.
The assoc array could follow same logic, i.e. point to null node.

For slices we could just stop supporting null and require [] instead, but I expect it would break quite a lot of code. For AAs, null is part of its design as a reference type. I'm not sure how you would get around that elegantly.

November 29, 2021

On Monday, 29 November 2021 at 13:11:12 UTC, user1234 wrote:

>

On Monday, 29 November 2021 at 12:51:47 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 29 November 2021 at 12:30:42 UTC, user1234 wrote:

>

static casts, devirtualization, are reasons for built-in
Also, since it would be a standard library construct a good compiler could have a special path for those. So it should remain the same.

If there must be a special path then it's already a failed library solution, not to say a lie. You make think to the user that classes is a library thing but it's not.

BTW, to be clear: yes I know that AliasSeq borrows such a special path in the compiler...but that rather tendd to show that the opposite is required: from library to builtin feature.

November 29, 2021

On Monday, 29 November 2021 at 13:11:47 UTC, Alexandru Ermicioi wrote:

>

But isn't a slice basically a struct with pointer and length?
Therefore you can consider that a slice is never null, but rather internal ptr field is, while length is 0.
The assoc array could follow same logic, i.e. point to null node.

any ops could then be implemented in terms of operator overloading.

You can't overload operators for built-in types, like pointers. So if you do it this way, you would no longer be able to write ptr[start .. end]--instead, you'd have to write something like ptr.slice(start, end).

November 29, 2021

On Sunday, 28 November 2021 at 20:47:28 UTC, Ola Fosheim Grøstad wrote:

>

If there was a majority in favour of D3, with breaking changes, and a strong focus on meta-programming, then it would make a lot of sense to streamline the language.

[..]

What do you think?

From the top of my head, my list looks like this:

  1. (Perhaps not D3 worthy - can be done in D2 as well, without removing existing funcitonality) replace all of the current reflection functionality (__traits(..), is(..), std.traits, etc.) with a cleaner CTFE-based API, along the lines of Stefan's core.reflect: https://github.com/UplinkCoder/druntime/tree/core_reflect/src/core/reflect
    Than add syntax sugar on top, after we develop experience with using it.

  2. Type qualifiers. I really like D's type qualifiers, including shared, but after using TypeScript at work for the past 2-3 years, I feel their approach is more flexible - simply offer head-only type qualifiers and build transitive ones on top:

    // Generic mapped type:
    // https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
    type IdentityObject<T> = {
        [K in keyof T]: T[K];
    };
    
    // Non-transitive read-only (const) type constructor
    type ReadOnly<T> = {
        readonly [K in keyof T]: T[K];
    };
    
    // Deep (transitive) read-only type constructor
    type DeepReadOnly<T> = {
        readonly [K in keyof T]: DeepReadOnly<T[K]>;
    };
    

    Full example in TS playground.

    In D3 perhaps this would like this:

    // aggregateOf(T) yields `struct`, `class`, `union` or `module`
    alias Const(T) = aggregateOf(T)
    {
        static foreach (fieldName, fieldType; T.fieldsOf)
            const fieldType $fieldName;
    };
    
    alias TransitiveConst(T) = aggregateOf(T)
    {
        static foreach (fieldName, fieldType; T.fieldsOf)
            const TransitiveConst!fieldType $fieldName;
    };
    
  3. Replace interface types and ad hoc Design-by-Introspection patterns like isInputRange, hasMember!(S1, "member") with TypeScript's object types: https://www.typescriptlang.org/docs/handbook/2/objects.html which offer a very powerful, yet elegant and concise way of describing object shapes.

  4. Replace ad hoc DIP1000 parameter storage class design with affine types. I haven't given it much thought, but ideally we should be able to write an Affine type constructor in library code and simply use it like as any other type constructor (e.g. tuple, sum type, etc.)

  5. Introduce some concept of compile-time dependency resolution / context abstraction (see https://docs.scala-lang.org/scala3/reference/contextual.html) so that things like the current allocator, scheduler, request/response context, etc., can be implicitly provided to improve the ergonomics of such APIs. For example, one could specify that in one scope the current implementation of associative arrays is a GC-managed hashmap, while in other a unique_ptr to red-black tree value container, like std::map, all while using the same K[V] x = [key1: value1] syntax.

November 29, 2021

On Monday, 29 November 2021 at 13:51:30 UTC, Paul Backus wrote:

>

On Monday, 29 November 2021 at 13:11:47 UTC, Alexandru Ermicioi wrote:

>

But isn't a slice basically a struct with pointer and length?
Therefore you can consider that a slice is never null, but rather internal ptr field is, while length is 0.
The assoc array could follow same logic, i.e. point to null node.

any ops could then be implemented in terms of operator overloading.

You can't overload operators for built-in types, like pointers. So if you do it this way, you would no longer be able to write ptr[start .. end]--instead, you'd have to write something like ptr.slice(start, end).

Sorry, kinda hard to remember that this is thread based conversation. I was talking in context where frontend does lower down built-in types to struct implementations of said builtin types.