November 30, 2022
One idea: offer a way to transform template arguments prior to passing them to the parameter.

```d
Foo!(const(int));
struct Foo(T |= Unqual) {}
```

Becomes:

```d
Foo!(Unqual!(const(int)));

struct Foo(T) {}
```

November 29, 2022

On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:

>

I've written most of a DIP for one. Should I:

I really wish that instead of adding more language features, we would improve the language so that things like this are implementable in the language.

I'm not sure about the argument that not everyone might use the same type if it's implemented as a custom type. Even if one were to argue that not everyone uses Phobos, the implementation can go into Druntime, which is an extension of the compiler, which solves this problem.

The example in the DIP about null pointers is wrong. It can still be useful to distinguish between non-null pointers, null pointers, and some third state such as "no pointer". Nullable!(Nullable!(Nullable!int)) foo is perfectly valid.

We don't even need a standardized NonNull type or trait or whatever. Leverage existing D features instead:

template nullIsValid(T)
{
    static if (is(T == struct))
        enum nullIsValid = {
            try
            {
                union U
                {
                    ubyte[T.sizeof] bytes = 0;
                    T t;
                }
                U u;
                assert(u.t); // call invariant
                return true; // no exception was thrown - null is a valid state
            }
            catch (Throwable e)
                return false; // exception was thrown - null is an INVALID state
        }();
    else
        enum nullIsValid = true;
}

or something like that. Currently it doesn't work because you can't call struct invariants directly, and can't catch assert(false) in CTFE. But, these are fixable and examples of things that would improve metaprogramming at a fundamental, building-block level and enable building more cool high-level types and data structures, not just sum types.

November 29, 2022
On Tue, Nov 29, 2022 at 11:56:40PM +0000, Vladimir Panteleev via Digitalmars-d wrote:
> On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:
> > I've written most of a DIP for one. Should I:
> 
> I really wish that instead of adding more language features, we would improve the language so that things like this are implementable *in* the language.
[.[..]

+1, I think this is a better approach.  If a library type can't do what a built-in type does, then extend the language until it can. As Andrei said in TDPL: "experience has shown time and again that offering many magic types that are unattainable to user code is a frustrating proposition and a sign of poor language design" [TDPL, 2010 ed, p.239].


T

-- 
Knowledge is that area of ignorance that we arrange and classify. -- Ambrose Bierce
November 30, 2022

On Tuesday, 29 November 2022 at 23:56:40 UTC, Vladimir Panteleev wrote:

>

On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:

>

I've written most of a DIP for one. Should I:

I really wish that instead of adding more language features, we would improve the language so that things like this are implementable in the language.

I'm not sure about the argument that not everyone might use the same type if it's implemented as a custom type. Even if one were to argue that not everyone uses Phobos, the implementation can go into Druntime, which is an extension of the compiler, which solves this problem.

The example in the DIP about null pointers is wrong. It can still be useful to distinguish between non-null pointers, null pointers, and some third state such as "no pointer". Nullable!(Nullable!(Nullable!int)) foo is perfectly valid.

We don't even need a standardized NonNull type or trait or whatever. Leverage existing D features instead:

template nullIsValid(T)
{
    static if (is(T == struct))
        enum nullIsValid = {
            try
            {
                union U
                {
                    ubyte[T.sizeof] bytes = 0;
                    T t;
                }
                U u;
                assert(u.t); // call invariant
                return true; // no exception was thrown - null is a valid state
            }
            catch (Throwable e)
                return false; // exception was thrown - null is an INVALID state
        }();
    else
        enum nullIsValid = true;
}

or something like that. Currently it doesn't work because you can't call struct invariants directly, and can't catch assert(false) in CTFE. But, these are fixable and examples of things that would improve metaprogramming at a fundamental, building-block level and enable building more cool high-level types and data structures, not just sum types.

Why have slices as builtin, it should be a template that nobody can read or write themselves

On top of an exception hidden within..

November 30, 2022

On Wednesday, 30 November 2022 at 00:17:04 UTC, ryuukk_ wrote:

>

On Tuesday, 29 November 2022 at 23:56:40 UTC, Vladimir Panteleev wrote:

>

On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:

>

I've written most of a DIP for one. Should I:

I really wish that instead of adding more language features, we would improve the language so that things like this are implementable in the language.

I'm not sure about the argument that not everyone might use the same type if it's implemented as a custom type. Even if one were to argue that not everyone uses Phobos, the implementation can go into Druntime, which is an extension of the compiler, which solves this problem.

The example in the DIP about null pointers is wrong. It can still be useful to distinguish between non-null pointers, null pointers, and some third state such as "no pointer". Nullable!(Nullable!(Nullable!int)) foo is perfectly valid.

We don't even need a standardized NonNull type or trait or whatever. Leverage existing D features instead:

template nullIsValid(T)
{
    static if (is(T == struct))
        enum nullIsValid = {
            try
            {
                union U
                {
                    ubyte[T.sizeof] bytes = 0;
                    T t;
                }
                U u;
                assert(u.t); // call invariant
                return true; // no exception was thrown - null is a valid state
            }
            catch (Throwable e)
                return false; // exception was thrown - null is an INVALID state
        }();
    else
        enum nullIsValid = true;
}

or something like that. Currently it doesn't work because you can't call struct invariants directly, and can't catch assert(false) in CTFE. But, these are fixable and examples of things that would improve metaprogramming at a fundamental, building-block level and enable building more cool high-level types and data structures, not just sum types.

Why have slices as builtin, it should be a template that nobody can read or write themselves

On top of an exception hidden within..

I don't think having a language for compiler writers is compelling for non-compiler writers

There is value in having common constructs implemented as first class language feature

  • better error message
  • better debugging
  • easier to integrate with tooling
  • everyone agree on a syntax
  • performance

When all the std eats the budget of template soup, what's left for me? using templates on top of templates on top of other templates, then users complain it takes 60 seconds to compile

It's important to showcase metaprogramming capabilities, but not everything has to be a template, specially for something as basic as tagged union

November 30, 2022
On Wednesday, 30 November 2022 at 00:10:47 UTC, H. S. Teoh wrote:
> On Tue, Nov 29, 2022 at 11:56:40PM +0000, Vladimir Panteleev via Digitalmars-d wrote:
>> On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:
>> > I've written most of a DIP for one. Should I:
>> 
>> I really wish that instead of adding more language features, we would improve the language so that things like this are implementable *in* the language.
> [.[..]
>
> +1, I think this is a better approach.  If a library type can't do what a built-in type does, then extend the language until it can. As Andrei said in TDPL: "experience has shown time and again that offering many magic types that are unattainable to user code is a frustrating proposition and a sign of poor language design" [TDPL, 2010 ed, p.239].
>
>
> T

Damn, this Andrei guy, he knew one thing or two...
November 29, 2022
On Wed, Nov 30, 2022 at 12:42:38AM +0000, deadalnix via Digitalmars-d wrote:
> On Wednesday, 30 November 2022 at 00:10:47 UTC, H. S. Teoh wrote:
[...]
> > +1, I think this is a better approach.  If a library type can't do what a built-in type does, then extend the language until it can. As Andrei said in TDPL: "experience has shown time and again that offering many magic types that are unattainable to user code is a frustrating proposition and a sign of poor language design" [TDPL, 2010 ed, p.239].
[...]
> Damn, this Andrei guy, he knew one thing or two...

And to elaborate a little, for those people who groan at "yet another library type": a common objection is that a library type has poorer error messages.  Well, it's just the same thing in different clothes: if a library type can't have good error messages, why is that?  Because the language cannot express certain things, or can't do it well, so the library author's hands are tied.  Giving up and pushing the type into the language is merely avoiding the problem (now the compiler writer has to solve the same problems, only in the compiler -- the amount of effort required is equivalent).  What actually addresses the problem is: fix the language so that the library author *can* provide good error messages.

Because this isn't just about adding sumtype or whatever other magic type, this is about making it possible for *any* user type to provide the same level of functionality as built-in types.  It's about empowering the library writer so that he can replicate the power of a built-in type, integrated so well into the language that it feels like native type.  This includes containers that behave like built-in arrays, ARC'd types that behave like pointers, etc..  Solve this at the core, and it will enable progress on many other fronts.  Fail at this, and you're doomed to putting out individual fires one by one, ala whack-a-mole.  Today it's sumtypes, tomorrow it's ARC types, the next day it's head-immutable, it will never end.


T

-- 
Don't drink and derive. Alcohol and algebra don't mix.
November 30, 2022
On Wednesday, 30 November 2022 at 00:10:47 UTC, H. S. Teoh wrote:
> On Tue, Nov 29, 2022 at 11:56:40PM +0000, Vladimir Panteleev via Digitalmars-d wrote:
>> On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:
>> > I've written most of a DIP for one. Should I:
>> 
>> I really wish that instead of adding more language features, we would improve the language so that things like this are implementable *in* the language.
> [.[..]
>
> +1, I think this is a better approach.  If a library type can't do what a built-in type does, then extend the language until it can. As Andrei said in TDPL: "experience has shown time and again that offering many magic types that are unattainable to user code is a frustrating proposition and a sign of poor language design" [TDPL, 2010 ed, p.239].
>
>
> T

I don't dispute this, but there's a bit of a gulf between saying it and it actually happening. There needs to be a specific list of things that need to be changed, preferably as bug reports, otherwise Walter will complain about it getting lost in old forum posts.
November 30, 2022

On Wednesday, 30 November 2022 at 01:09:03 UTC, H. S. Teoh wrote:

>

This includes containers that behave like built-in arrays, ARC'd types that behave like pointers, etc.. Solve this at the core, and it will enable progress on many other fronts.

How can we improve the core?

November 30, 2022
On 11/30/22 00:56, Vladimir Panteleev wrote:
> On Monday, 28 November 2022 at 09:27:11 UTC, Walter Bright wrote:
>> I've written most of a DIP for one. Should I:
> 
> I really wish that instead of adding more language features, we would improve the language so that things like this are implementable *in* the language.

Well, ideally both. Tagged unions are fundamental enough to get some syntactic sugar. So are tuples. But except for syntax, I agree that user-defined types should be able to benefit as well.

Here, I guess this would mean to add some mechanism to allow the language to understand which `union` member is currently active. This would also help with precise GC.

Another consideration is compile times. Sometimes it makes sense to build things into the language because you don't want to interpret them again and again if you can compile them once into the compiler frontend.

I also don't like magic though. Ideally it should be possible to write a shallow wrapper `struct` (template) around any other type without losing any functionality.