February 23, 2021
On Monday, 22 February 2021 at 18:01:34 UTC, SealabJaster wrote:
> On Monday, 22 February 2021 at 16:27:49 UTC, Andrei Alexandrescu wrote:
>> Of possible interest:
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2320r0.pdf
>
> "Readability. Obviously, we’d like our programs to be readable. We want syntax that is both visually distinctive yet comprehensible."
>
> Can anyone more experienced with C++ confirm that this is in any way readable and easy to understand? Because my definition of "readability" appears to be vastly different, especially when I imagine it being used alongside the rest of C++'s symbol spam.
>
> "f<([:Refl:])>();"

đŸ¤£

Is this real life


February 23, 2021
On Tuesday, 23 February 2021 at 10:14:50 UTC, Imperatorn wrote:
>
> Is this real life

C++ is quickly becoming that annoying legacy langage that no one likes.
I would be incredibly wary starting a C++ project in 2021 ; in my exprience literally anything else is a more productive use of your time.

Even in the audio space which is 95% C++, the top product is FLStudio, a product that was originally from Delphi.
Friendlier languages lead to friendlier products for some reasons.
February 23, 2021
On Tuesday, 23 February 2021 at 10:24:26 UTC, Guillaume Piolat wrote:
> On Tuesday, 23 February 2021 at 10:14:50 UTC, Imperatorn wrote:
>>
>> Is this real life
>
> C++ is quickly becoming that annoying legacy langage that no one likes.
> I would be incredibly wary starting a C++ project in 2021 ; in my exprience literally anything else is a more productive use of your time.
>
> Even in the audio space which is 95% C++, the top product is FLStudio, a product that was originally from Delphi.
> Friendlier languages lead to friendlier products for some reasons.

The effort to avoid C++ in some domains is very high, for example on Windows, it seems every effort from DevDiv to improve the overall experience gets botched by WinDev pushing their C++ agenda.

Now it remains to be seen what uphill battles the newly created Microsoft Rust team will need to face as well.

This is just one example among many, either one is prepared to be the snowflake that does everything alone, and spends development money getting stuff to work, or just integrate the existing ecosystem and proceed to spend customer's money on actual product development.

I cannot bill hours on "working around existing C++ SDK, because there is better out there".
February 23, 2021
On Monday, 22 February 2021 at 16:27:49 UTC, Andrei Alexandrescu wrote:
> Of possible interest:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2320r0.pdf

Hmm at a glance it looks close where I am at with typefunctions.

The syntactic difference is that the unary ^ is an either an implicit conversion or an explicit cast.

If they play their cards right and integrate their meta-info properly with constexpr it's going to beat D.

February 23, 2021
On Monday, 22 February 2021 at 23:44:45 UTC, Paul Backus wrote:
> On Monday, 22 February 2021 at 23:32:39 UTC, Max Haughton wrote:
>> On Monday, 22 February 2021 at 21:59:41 UTC, Paul Backus wrote:
>>> On Monday, 22 February 2021 at 21:34:47 UTC, Max Haughton wrote:
>>>> On Monday, 22 February 2021 at 16:27:49 UTC, Andrei Alexandrescu wrote:
>>>>> Of possible interest:
>>>>>
>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2320r0.pdf
>>>>
>>>> Exposing reflection information via CTFE seems like a much more workable solution - i.e. you just write regular D code. This is what Stefan's work effectively culminates in.
>>>
>>> Or, in other words: procedural macros. (Shh, don't tell Walter.)
>>
>> They aren't macros though - at least in my mind a macro is effectively a shortcut into the bowels of the compiler whereas in this case the compiler wouldn't care what you do with the information after it gives it to you since it's just regular D code.
>
> Aren't macros in Lisp just regular Lisp code, too? :)
>
> As far as I'm concerned, a procedural macro is a function that
>
> 1. runs at compile time,
> 2. takes AST nodes as input, and
> 3. produces AST nodes as output.
>
> Type functions fit those criteria perfectly. Currently, they only work on a subset of AST nodes (types), so they're not a *complete* implementation of procedural macros, but generalize them enough and that's what you'll get.

They don't exactly take AST nodes.
They take a constrained (stabilized) datastructure which reflects a subset of the ast.
At least conceptually.
They don't create ast nodes, but regular values, which may be converted to ast-nodes in the case where they are statically available. (currently only types)

My currently exploration leads me to a path where you can _extend_ open scopes within typefunction by using special functions which map provide a stable mapping to compiler intrinsics.
such as __struct* __add_struct(string name, __symbol[] members);
the __struct* will not be a proper struct type unless
__type__ __add_to_scope(__scope Scope, __struct* s);
has been called.

At which point any modification of the __struct* is an error and will abort compilation.

I am still searching for a solution which is more declarative, but I fear for heavy usage (10_000 new types and declarations added) scenarios the procedural imperative style is just more optimizable.

I am always open to syntax suggestions, as I don't like the one I have :)
February 23, 2021
On Tuesday, 23 February 2021 at 13:58:34 UTC, Stefan Koch wrote:
>
> If they play their cards right and integrate their meta-info properly with constexpr it's going to beat D.

Can you explain further why it is going to beat D (I assume in terms of functionality, not aesthetics).
February 23, 2021
On Tuesday, 23 February 2021 at 15:04:46 UTC, IGotD- wrote:
> On Tuesday, 23 February 2021 at 13:58:34 UTC, Stefan Koch wrote:
>>
>> If they play their cards right and integrate their meta-info properly with constexpr it's going to beat D.
>
> Can you explain further why it is going to beat D (I assume in terms of functionality, not aesthetics).

Because the conversion to reflection values meta::info or whatever it was called happens inside the compiler.
It's not shackled to templates.

And therefore they can have very fast generation of these without inuring recursive evluate-semantic() function calls.
February 23, 2021
On Tuesday, 23 February 2021 at 10:24:26 UTC, Guillaume Piolat wrote:
> On Tuesday, 23 February 2021 at 10:14:50 UTC, Imperatorn wrote:
>>
>> Is this real life
>
> C++ is quickly becoming that annoying legacy langage that no one likes.
> I would be incredibly wary starting a C++ project in 2021 ; in my exprience literally anything else is a more productive use of your time.

I agree that C++ is less productive than many other languages if you want to write the whole application in C++. It is quite ok for "engine parts", e.g. DSP etc.

But I don't think this syntax thing is going to be a big issue. Editors will colour them and it static reflection is most likely something library authors will use.

> Even in the audio space which is 95% C++, the top product is FLStudio, a product that was originally from Delphi.

I though most people use Abelton Live? Although Cubase is probably better for composing than both Abelton and FLStudio.

February 23, 2021
On Tuesday, 23 February 2021 at 14:14:13 UTC, Stefan Koch wrote:
> On Monday, 22 February 2021 at 23:44:45 UTC, Paul Backus wrote:
>>
>> Aren't macros in Lisp just regular Lisp code, too? :)
>>
>> As far as I'm concerned, a procedural macro is a function that
>>
>> 1. runs at compile time,
>> 2. takes AST nodes as input, and
>> 3. produces AST nodes as output.
>>
>> Type functions fit those criteria perfectly. Currently, they only work on a subset of AST nodes (types), so they're not a *complete* implementation of procedural macros, but generalize them enough and that's what you'll get.
>
> They don't exactly take AST nodes.
> They take a constrained (stabilized) datastructure which reflects a subset of the ast.
> At least conceptually.
> They don't create ast nodes, but regular values, which may be converted to ast-nodes in the case where they are statically available. (currently only types)

This is also how macros work in some Lisp implementations. For example, in Racket, the AST nodes (called "syntax objects") are converted to S-expressions by the function `syntax->datum`, the S-expressions are manipulated by CTFE, and the result is converted back into an AST node by `datum->syntax`. [1]

> My currently exploration leads me to a path where you can _extend_ open scopes within typefunction by using special functions which map provide a stable mapping to compiler intrinsics.
> such as __struct* __add_struct(string name, __symbol[] members);
> the __struct* will not be a proper struct type unless
> __type__ __add_to_scope(__scope Scope, __struct* s);
> has been called.

I haven't fully thought this through, but would it be possible to overload `mixin` to do this? E.g.,

    import core.ast: Struct, Type;

    // some type function
    Struct pair(Type t) { ... }

    alias PairOfInts = mixin(pair(int));

Conceptually, `mixin` already means "take this stuff and inject it into the current scope," and grammatically it's allowed to appear as both an expression and a type.

> At which point any modification of the __struct* is an error and will abort compilation.

If __struct is only the "user-space" representation, and not the real AST node, I don't see why this is necessary, since modifying the __struct after mixing it in wouldn't have any affect on the actual AST.

> I am still searching for a solution which is more declarative, but I fear for heavy usage (10_000 new types and declarations added) scenarios the procedural imperative style is just more optimizable.
>
> I am always open to syntax suggestions, as I don't like the one I have :)

In Lisp, the declarative syntax is typically implemented as syntax sugar on top of the procedural syntax, using the `quasiquote` or `backquote` macro. [2][3] In D, one could imagine doing something similar with string mixins: generate the procedural code at compile time from a declarative DSL, then mix it in.

[1] https://docs.racket-lang.org/guide/stx-obj.html
[2] https://docs.racket-lang.org/guide/qq.html
[3] https://www.ccis.northeastern.edu/home/futrelle/teaching/lisp/cltl/clm/node190.html#BACKQUOTE
February 23, 2021
On Tuesday, 23 February 2021 at 15:35:43 UTC, Paul Backus wrote:
> On Tuesday, 23 February 2021 at 14:14:13 UTC, Stefan Koch wrote:
>> On Monday, 22 February 2021 at 23:44:45 UTC, Paul Backus wrote:
>
> I haven't fully thought this through, but would it be possible to overload `mixin` to do this? E.g.,
>
>     import core.ast: Struct, Type;
>
>     // some type function
>     Struct pair(Type t) { ... }
>
>     alias PairOfInts = mixin(pair(int));
>
> Conceptually, `mixin` already means "take this stuff and inject it into the current scope," and grammatically it's allowed to appear as both an expression and a type.

Yes it would be possible to reuse mixin, but iirc mixins convert non-string expressions to string which would introduce ambiguity, if I special case it __struct, or __type__.

>> At which point any modification of the __struct* is an error and will abort compilation.
>
> If __struct is only the "user-space" representation, and not the real AST node, I don't see why this is necessary, since modifying the __struct after mixing it in wouldn't have any affect on the actual AST.
>
The restriction is imposed to avoid confusing situations, due to the closeness of the mapping to real compiler entities you cannot finalize the same struct* twice and such things.
Modifying a __struct after it has been finalized or 'mixed-in' is either useless or a bug.