November 05, 2020
On Thursday, 5 November 2020 at 04:07:06 UTC, Q. Schroll wrote:
> Here is the DIP PR: https://github.com/dlang/DIPs/pull/194 and the DIP document: https://github.com/Bolpat/DIPs/blob/TokenMixins/DIPs/DIP-1NN2-QFS.md
>
> Please let me know of any suggestions that come to your mind in this thread or the PR discussion.

This seems like an extremely narrow and special-purpose feature for something that could just as easily be addressed by a more general feature, like string interpolation or quasiquotation.

It also shares the same basic weakness as format strings, which is that every time you see (for example) an `op` in the mixin body, you have to look somewhere else in the code to see what it's going to be replaced with. And unlike a `%s` format specifier, there's no easy way to distinguish a replacement token in the mixin body from a normal identifier.
November 05, 2020
On Thursday, 5 November 2020 at 06:04:47 UTC, Paul Backus wrote:

> This seems like an extremely narrow and special-purpose feature for something that could just as easily be addressed by a more general feature, like string interpolation or quasiquotation.

I fully agree.

> It also shares the same basic weakness as format strings, which is that every time you see (for example) an `op` in the mixin body, you have to look somewhere else in the code to see what it's going to be replaced with. And unlike a `%s` format specifier, there's no easy way to distinguish a replacement token in the mixin body from a normal identifier.

I agree. But that's also how templates behave and I have not heard of anyone complaining about that.

--
/Jacob Carlborg
November 05, 2020
On Thursday, 5 November 2020 at 04:07:06 UTC, Q. Schroll wrote:
> Here is the DIP PR: https://github.com/dlang/DIPs/pull/194 and the DIP document: https://github.com/Bolpat/DIPs/blob/TokenMixins/DIPs/DIP-1NN2-QFS.md
>
> Please let me know of any suggestions that come to your mind in this thread or the PR discussion.

Isn't it quite rare to have the mixin location and the string, to be mixed in, at the same place? For example:

mixin("int a = 3;"); // rare

string generate(string name)
{
    return "int " ~ name " = 3;"; // code is here
}

mixin(generate("a")); // mixin location is here, more common

How will your solution help with that?

Perhaps we can turn the problem around. Instead of doing some form of highly specialized string interpolation, that only works in one place, instead focus on removing the need to use strings in the first place.

In the cases I had the need to use a string mixins, most of the code would have worked with a template mixin, but it was just the identifier that caused the need to move to string mixins. Example:

mixin template property(T)
{
    private T a_;
    T a() { return a_; }
}

class Foo
{
    mixin property!int;
}

To be able to specify the name of the property the whole template mixin needs to be replaced with a string mixin. What if we instead could allow string mixins in more locations. Example:

mixin template property(T, string name)
{
    private T mixin(name)_;
    T mixin(name)() { return mixin(name)_; }
}

class Foo
{
    mixin property!(int, "a");
}

I would not call the above a new language feature, just removing some limitations.

Or, the solution to all of the above (and many more issues): AST transformations [1].

[1] https://wiki.dlang.org/DIP50

--
/Jacob Carlborg

November 05, 2020
On Thursday, 5 November 2020 at 12:51:38 UTC, Jacob Carlborg wrote:
> Isn't it quite rare to have the mixin location and the string, to be mixed in, at the same place? For example:

That's probably the majority of my uses and a lot of times it is specifically to use the name of a declaration with most everything else being inside the static string.
November 05, 2020
On Thursday, 5 November 2020 at 12:51:38 UTC, Jacob Carlborg wrote:
>
> Perhaps we can turn the problem around. Instead of doing some form of highly specialized string interpolation, that only works in one place, instead focus on removing the need to use strings in the first place.
>
> In the cases I had the need to use a string mixins, most of the code would have worked with a template mixin, but it was just the identifier that caused the need to move to string mixins. Example:
>
> mixin template property(T)
> {
>     private T a_;
>     T a() { return a_; }
> }
>
> class Foo
> {
>     mixin property!int;
> }
>
> To be able to specify the name of the property the whole template mixin needs to be replaced with a string mixin. What if we instead could allow string mixins in more locations. Example:
>
> mixin template property(T, string name)
> {
>     private T mixin(name)_;
>     T mixin(name)() { return mixin(name)_; }
> }
>
> class Foo
> {
>     mixin property!(int, "a");
> }
>
> I would not call the above a new language feature, just removing some limitations.
>
> Or, the solution to all of the above (and many more issues): AST transformations [1].
>
> [1] https://wiki.dlang.org/DIP50
>
> --
> /Jacob Carlborg

Something like the code below seems innocuous to me and is not allowed in template mixins.


```
mixin template loop1(long n, T = double)
{
  T x = 0;
  for(long i = 0; i < n; ++i)
  {
    x += cast(T)(i)^^2.0;
  }
}

```

Maybe there is a case for relaxing the rules on for, while, and so on?
November 06, 2020
On Thursday, 5 November 2020 at 12:51:38 UTC, Jacob Carlborg wrote:
> Isn't it quite rare to have the mixin location and the string, to be mixed in, at the same place?

I'd say mixin(generate(args)) and mixin("..pattern..", hole, "..pattern..") are currently the two standard uses of string mixins. While the first is perfectly fine, the latter lacks readability greatly, since **code to be read is in string literals** where it shouldn't be. In the first use-case, generate may stitch together the generated code in a way that might be hard to follow, but that's hard to improve. My proposal makes code, well, code. Interpolated strings don't help that either. Interpolated strings' mission is to generate strings which has its merits and use-cases well beyond string mixins.

To convince myself I've just run

    grep 'mixin(.*"' *.d

and

    grep 'mixin.*q{' *.d

over Phobos (std/) and got 169 and 10 results respectively. (This search is surface-level but finds good candidates.) I reviewed every one of them manually and found 133 of 169 and 8 of 10 would probably have been written with my proposed syntax. Since Phobos is a meta-programming heavy library, I'd consider it a representative target, as mixin is without doubt a meta-programming tool. To be fair, 78 of the 133 matches follow one of the operator mixin patterns ("lhs" ~ op ~ "rhs" or op~"value") which is probably the most common and obvious use-case.
November 06, 2020
On Thursday, 5 November 2020 at 12:51:38 UTC, Jacob Carlborg wrote:
> To be able to specify the name of the property the whole template mixin needs to be replaced with a string mixin. What if we instead could allow string mixins in more locations?

Something like that has been proposed before, called "mixin identifiers"; everywhere an Identifier would be valid, one could use a string mixin to generate and splice in the identifier. Of your example,

mixin template property(T, string name)
{
    private T mixin(name)_;
    T mixin(name)() { return mixin(name)_; }
//    -----------
}

only the highlighted part would word. The other parts don't make sense; mixins don't "connect" with surrounding tokens. If `name` is "prop", `mixin(name)_` cannot become `prop_`. No kind of mixin does that; not even my DIP proposes that.

Borrowing from your example, you'd do:

mixin template property(T, string name)
{
    mixin[name, name_ = name ~ "_"]
    {
        private T name_;
        T name() { return name_; }
    }
}

which reads very well, I guess. I'm not opposed to mixin identifiers, since they tackle a not-so-rare use-case. Another proposal was being able to mix in the name of something that's being declared. In your example, that would be the variable name_ and the function name(), but it wouldn't tackle `return name_;`. I'd call it mixin declarations, but that name is already taken by string mixins that are in a declarative scope (module, struct, union, class, interface, template). Mixin identifiers would e.g. allow you to mix in parameter type names and parameter names. Since @ isn't part of an attribute, @mixin(..) would also work, since the grammar says @ Identifier is valid. (Funny enough, "@ safe" [note the space] works perfectly, but no-one uses it.)

Maybe I'll make Mixin Identifiers part of the DIP. Let me know what you think.
November 06, 2020
On Friday, 6 November 2020 at 01:06:28 UTC, Q. Schroll wrote:
>
> Something like that has been proposed before, called "mixin identifiers"; everywhere an Identifier would be valid, one could use a string mixin to generate and splice in the identifier. Of your example,
>
> mixin template property(T, string name)
> {
>     private T mixin(name)_;
>     T mixin(name)() { return mixin(name)_; }
> //    -----------
> }
>
> only the highlighted part would word. The other parts don't make sense; mixins don't "connect" with surrounding tokens. If `name` is "prop", `mixin(name)_` cannot become `prop_`. No kind of mixin does that; not even my DIP proposes that.

This is trivially fixed by changing `mixin(name)_` to `mixin(name, "_")`.

> Maybe I'll make Mixin Identifiers part of the DIP. Let me know what you think.

Better to make them two separate DIPs. They're completely independent features, after all.
November 06, 2020
On Friday, 6 November 2020 at 00:50:16 UTC, Q. Schroll wrote:
> On Thursday, 5 November 2020 at 12:51:38 UTC, Jacob Carlborg wrote:
>> Isn't it quite rare to have the mixin location and the string, to be mixed in, at the same place?
>
> I'd say mixin(generate(args)) and mixin("..pattern..", hole, "..pattern..") are currently the two standard uses of string mixins. While the first is perfectly fine, the latter lacks readability greatly, since **code to be read is in string literals** where it shouldn't be. In the first use-case, generate may stitch together the generated code in a way that might be hard to follow, but that's hard to improve. My proposal makes code, well, code. Interpolated strings don't help that either. Interpolated strings' mission is to generate strings which has its merits and use-cases well beyond string mixins.
>
> To convince myself I've just run
>
>     grep 'mixin(.*"' *.d
>
> and
>
>     grep 'mixin.*q{' *.d
>
> over Phobos (std/) and got 169 and 10 results respectively. (This search is surface-level but finds good candidates.) I reviewed every one of them manually and found 133 of 169 and 8 of 10 would probably have been written with my proposed syntax. Since Phobos is a meta-programming heavy library, I'd consider it a representative target, as mixin is without doubt a meta-programming tool. To be fair, 78 of the 133 matches follow one of the operator mixin patterns ("lhs" ~ op ~ "rhs" or op~"value") which is probably the most common and obvious use-case.

I like your DIP. It's one of those simple syntax changes that have a huge effect on readability without introducing complex concepts. It is also not that uncommon intellectual concept. It is similar to a with(e) {} or catch(e) {}.
People who object to your DIP for "difficulty to make the link between expression in [] and the statements" reasons, should be high up in arms against with statement, as there the readability is worse as there is not even a hint where the head expression was omitted.


You should add these statistics to the dip, to bring home the point. Choose 1 or 2 (or 3) specially juicy examples from that list showing the undeniable readability advantage it brings.
1 2
Next ›   Last »