April 03, 2019
On Wednesday, 3 April 2019 at 20:28:35 UTC, Rose wrote:
> On Wednesday, 3 April 2019 at 20:11:02 UTC, Rubn wrote:
>> On Wednesday, 3 April 2019 at 20:10:08 UTC, Rubn wrote:
>>> On Tuesday, 2 April 2019 at 20:43:14 UTC, Walter Bright wrote:
>>>> On 4/2/2019 4:05 AM, Andrei Alexandrescu wrote:
>>>>> You forgot to mention that top-level "const" is ignored in function parameters (for the signature and mangling but not the implementation).
>>>>
>>>> Curiously, it is present in the name mangling for dmc++ and dmd (for extern(D)), but it should be fixed for dmd.
>>>>
>>>> https://issues.dlang.org/show_bug.cgi?id=19785
>>>>
>>>>
>>>>> Now the fact that "42" is just ignored in the declaration below is indistinguishable from conspiracy:
>>>>> 
>>>>> void fun(int a[42]);
>>>>
>>>> Ironically, it is not ignored in the C++ mangling if it's a ref to int[42].
>>>
>>> Not ironically, because you can't have a reference to a pointer :). It makes sense if you understand that:
>>>
>>>    void foo( int a[] );
>>>
>>> Is not a parameter to an array. After your whole spiel about ferraris, engines, and how their users won't see the internal workings of the engine. I'd have hoped better from you than you pointing at the top level fluffy user-friendly error message and saying LOOK LOOK it says array so it must be an array!
>>
>> A pointer to a reference*.
>
> The Dunning-Kruger is strong with this one.
>
> Arrogance completes ignorance.

Not as much as walter and andrei. I really hope I never reach a point where I think I know more than anyone else that I would simply dismiss people's discussions because of some accomplishment. If you think you have nothing more to learn, then step aside for those that do.
April 03, 2019
On 03.04.19 22:36, Timon Gehr wrote:
> On 03.04.19 21:56, Rubn wrote:
>> On Tuesday, 2 April 2019 at 07:58:21 UTC, Walter Bright wrote:
>>> On 4/1/2019 5:20 PM, Rubn wrote:
>>>> Let's put it this way, is const a type?
>>>
>>> No. It's a "type qualifier".
>>
>> Enough so that it is called a storage class>
> 
> Syntactically, it is both. However, annotating a variable with `const` will apply the type qualifier to its type without

_necessarily_

> affecting how it is stored.

(But it can, e.g. static const variables will be put into the readonly data section.)
April 04, 2019
On Mon, Apr 1, 2019 at 3:40 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 3/31/2019 6:30 PM, Manu wrote:
> >> A C++ ref can only appear at the top of a type AST, which is unlike any other type. Which exactly matches the only place a storage class can be!
> >
> > So, what you're saying is, C++ was able to implement storage class semantics, but without distinguishing storage class from the type, thereby making it accessible to any type construction or introspection machinery that the language has available?
> >
> > Apparently C++ was genius in this way; why would you invent storage class specifically to exclude ref from the ability to interact with type construction and introspection machinery? ref sucks because it can't interact with type construction or introspection. Every meta-interaction with ref is via kludgey hacks.
>
> Um, have you looked at the special, kludgey rules for refs that permeate the C++ spec? Just about every rule for types has a special case for refs. For example, C++ does type inference in various contexts. Sometimes the ref is inferred, sometimes it is skipped. Can you describe when it is inferred and when it isn't, and why?

I understand the rules are complex.
But I'm saying that 1; I don't believe we *must* implement the
complexity exactly the same way if ref were part of the type.
and 2; if you're being honest, you need to balance that complexity you
describe against the complexity introduced by the _idea_ of storage
class, every single detail relating to its implementation, and the
loss of language to interact with type construction and introspection.
Storage class and all related implementation and semantics are
*hugely* complicated, and I think it's worse because it's a parallel
system with an unrelated set of rules that you have to remember
distinctly, and no language for meaningful interaction. You can't
choose to ignore details about meta-interaction with storage class as
part of that complexity, they are major.
Whereas C++ ref rules are founded in type construction, which, while
needing to understand some special cases, don't require understanding
a whole parallel ecosystem.

I find it hard to judge that the storage class solution can be considered simpler than the complexity that you refer to from C++, and I also think it's a false comparison, because I suspect we could paint the rules simpler than C++ if we tried.

Storage class == text mixin, and the worst kinds of text mixins, because they usually affect the function signature. Because text mixins must form a complete expression, if you ever need to do text-mixin on a function signature, the **entire function** must be written as a string which is unreasonably hideous.

Storage class is the worst thing in D. I love to make over-inflated claims, but I say this with absolute conviction. There is nothing about D more upsetting than storage class; it is functionally incompatible with introspection and generative meta, and that's D's strongest value proposition. How can you say a feature that's fundamentally incompatible with meta-programming is great?

> > You mention the complexity of ref in C++, but that needs to be balanced against the entire concept of 'storage class' in D, and literally every single rule relating to it, since that's the counter-weight. If you take the aggregate of all rules and semantics related to 'storage class' in D, especially when including consideration that we have lost the ability to do type construction or introspection in storage classes, is that REALLY simpler than C++?
>
> Yes. Keep in mind that I implemented ref in C++, every last gory detail. I've earned my opinion of it.

The goal is to make language painless and enjoyable for authors, not necessarily for compiler developers, that's just a nice bonus.

I'm not saying it *must* be like C++ (I suspect a less-complex set of rules is possible), I'm just saying it's better. What it should NOT be, is a completely separate mechanism outside of the language like storage class.

Perhaps you can invent another meta-language for interacting with storage-class... I've tried to imagine it, but I really struggle to picture something satisfying.
April 04, 2019
On Thursday, 4 April 2019 at 07:21:34 UTC, Manu wrote:
>
> Perhaps you can invent another meta-language for interacting with storage-class... I've tried to imagine it, but I really struggle to picture something satisfying.

I wanted this a long time, declarations as template params.

fun!(ref int x);

Every part should be possible to introspect including storage class and variable name.

April 04, 2019
On Mon, Apr 1, 2019 at 4:10 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 3/31/2019 6:19 PM, Manu wrote:
> > Are you saying that it's impossible to design a solution where ref is part of the type and that's less complex than C++?
>
> I couldn't think of a way. I could have simply copied the C++ design. But why copy a nightmare of kludges?
>
>
> > Is the complexity is that ecosystem inherent, or is it somewhat informed by backwards-compatibility, and other C++ design constraints?
>
> There was no backwards compatibility issue when ref was designed. It's just a poor choice (like volatile).
>
>
> > The fact that I can write `struct Ref(T)` and that it propagates the type system in a natural way suggests to me that the design is not impossible.
>
> I have no idea why you want to do such things, but apparently you have a solution that works for you, so that's all good.
>
>
> >> Please show a use case. I can't think of one.
> > A use case for propagating ref in the type? You can't imagine why a template argument might want to distinguish `int` and `ref int`?
>
> Indulge me. Why would it?

Propagating compile time information as types is the fundamental of D's meta.
Not being able to propagate ref's is really problematic. Not being
able to declare a local ref is really problematic.

void fun(ref int x)
{
  bool b = is(typeof(x) == ref); // nope! seems so obvious (you should
watch their faces when I show them how to do it)

  int i = 10;
  ref int j = i; // nope! again, watch their faces when I say they can't do this

  ref auto resolveLongExpression =
long.expression().that[0].we().dont_want_to.repeat;  // nope!
  foreach(i; things)
  {
    resolveLongExpression++; // repeated access to a deep expression

    // use a pointer you say? pointers change semantics; assignment
and increment mean something different now
    // if there's any meta involved, then pointer's semantic
distinction is something you're gonna have to write `static if()`
nonsense to detect and special-case!
  }

  // other kinds of expressions that we don't want to repeat, but may
want to carry the ref-ness
  auto ref x = returnsValue();
  ++x; // increment local
  auto ref y = returnsRef();
  ++y; // increment reference
}

alias Param = Parameters!(fun)[0];
void g(Param arg) // nope!
{
  ... lots of code
}

this is obviously much better:

bool isRef(alias fn, int argIndex, int i = 0)
{
  static if (i == __traits(getParameterStorageClasses, fn, argIndex).length)
    enum isRef = false;
  else
    enum isRef = __traits(getParameterStorageClasses, fn, argIndex)[i]
== "ref" ? true : isRef!(fn, argIndex, i + 1);
}

string myFun = "void g(" ~ (isRef!(fun, 0) ? "ref " : "") ~ "Param arg)\n" ~
"{\n" ~
"    lots;\n" ~
"    of;\n" ~
"    code;\n" ~
"}\n";
mixin (myFun);

Whole function (or any other construction that fits this pattern) is a
string because some storage class appears in the declaration.
Say goodbye to autocomplete, debugging, refactoring, syntax
highlighting, readability, and editability/maintainability.


Sorry, I don't have a real-world case at hand right now, I didn't
start the thread complaining this time; I'm just supporting someone
who is feeling the same feels.
I've learned to try and avoid this stuff in D, because D just can't
reasonably do it. But it's very annoying to avoid, and it's a major
weakness of D's meta, and it's very disappointing to new users when
they work this out.


> > I don't know how you've never found yourself static-if-ing on ref-ness
> > of stuff in every bit of functional meta you've ever written. Ref
> > creates an out-of-language (we have no language features to interact
> > with 'storage class') suite of conditions that I frequently have to
> > wrangle my way through.
> > We have strong language mechanisms to reason about the type system,
> > there is no language to reason about storage class that's not a kludge
> > of awkward hacks and ugly meta utilities.
>
> If I was faced with that, I'd step back and re-assess why the design required such machinations.

This is like a general argument against meta-programming. You don't
get to decide when this stuff comes up in the wild; it just does.
The worst cases are usually when automating bindings between systems;
that might be to foreign languages, scripting solutions,
tooling/editor interactions, or perhaps some high-level application
scaffolding.
One of D's biggest attractions is the ability to use powerful
in-language meta-programming features to solve binding and boilerplate
tasks that would traditionally require external tooling. When I use D,
I lean into that promise HARD. The reason to choose D is to solve
particular categories of problems I can't possibly solve in other
languages.
Ref (and other storage classes) bite me in the arse every single time.
Imagine how much worse this will be when 'scope' proliferates!


> It reminds me of when I peruse Phobos, I'm disturbed by the overly complex code there - something Andrei referred to in the "generality creep" thread.

I'm not commenting on phobos complexity (which is indeed hideous, and
I avoid phobos).
There are a lot of programming tasks; one programming task is writing
programs, but another overwhelmingly popular and most tedious and
painful task is developing and maintaining bindings and boilerplate
interaction to large established ecosystems.
Basically everyone I know who has been drawn to D are initially
attracted by the ability to automate boilerplate and terrible cruft
from external tooling and reducing build complexity. That's the stuff
that sends them packing in search of a brighter future.
A lot of meta is used to automate boilerplate and binding machinery.

If a user is 'just writing programs', then C++ is just fine. They're attracted to D by the promise of simplifying or addressing the mountain of code that C++ _can't_ express. Boilerplate meta is one of the most common tasks that stokes initial interest in D. To dismiss that, is to misunderstand D's value proposition to a huge audience. This is certainly the case where D is discussed in the project I'm work on right now, and has been the case since I ever started discussing D with colleagues. It's the most immediate and painful problem they see an obvious solution for. You should value that use-case if you want to attract users.

Everything else D has to offer is a nice bonus that these people would
appreciate in time, but they need to be drawn in by successfully
solving the problems immediately before them that D appears to be
well-placed to solve.
I have watched so many cases of people trying out some such solution,
and then they encounter ref, I start to explain to them what they need
to do, they are surprised, then they're angry at me for wasting their
time, and then they lose interest.

Storage class is really, *really* bad. The terribleness of it in terms of the impression it leaves on people is really important. I've been trying to tell you this for so long, I don't think there's anything else I can do.


> If C++ does it better, I don't see how. I find the implementation code of the STL to be horrifying in its complexity. I don't know how to write such code without thinking "something has gone terribly wrong".

It's not about STL. I hope I've made that clear.
But that said, you have invented the most powerful meta-programming
language out there, you've gotta own that, and you can't be upset when
people try to apply it to solve specific problems it's uniquely
well-fit for.
I agree there's a HUGE danger of abusing D's meta-programming
features, I constantly have to restrain myself, but the kind of work I
refer to is not of that kind.


> If I may, I once talked to a Ferrari mechanic. He said that most engines inside, where customers didn't see the innards, were sloppily made. But that the Ferrari engine was a thing of beauty inside and a joy to work on. Ironically, Ferraris are also known for cheap, poorly done cab interiors. An unusual focus for a car company :-) but one that appeals to my inner engineer. The engine in my Dodge was built the same way, it's blueprinted with all top quality parts inside it, but the outside is plain jane, no chrome parts, no dress-up, etc.

That's a nice thought, but that's not important to this particular
class of problem.
What I'm talking about here is attracting users who are able to
successfully solve their long-standing and terribly painful problems.
Cases where storage class comes up as a problem is almost always of
that category. Apparently I seem to suffer this category of task 10x
more than the average guy.

I've tried to make this point before, and I'll try again;
Most programmers are not 'great' programmers, they're just
programmers, they're employees of businesses, at 5pm they go home and
hang out with the kids and shag the wife.
They're not too worried about building a ferrari engine; they mostly
just wanna get paid, they have a job to do, and they almost invariably
have an established ecosystem of existing cruft they interact with.
There is a high probability they have this rats-next of
hand-maintained boilerplate and tooling that they HATE maintaining,
and that's the angle I've continually had the most success gaining
interest from new users.

Our goal is to attract these people, and ideally, improve their ability to do a good job more quickly. We want them to feel more productive and make less mistakes, but we can't help them if they never come to the party!

D's key advantage out-of-the-gate as I have seen it for so many years,
is that it's *theoretically* possible to build bridges between
existing ecosystems where we can take a foothold against 40 years of
establishment.
This is the land of boilerplate and connective meta. I've written a lot of it.
They won't come to us if they need to swim the crocodile infested
river. We must build a bridge to them and make crossing the river
unreasonably simple and appear like the obvious thing to do.

Storage class hurts more than anything else towards this end.

Anyway... I'm going to bed. I'll complain about it again next year.
April 04, 2019
On Mon, Apr 1, 2019 at 7:00 AM Atila Neves via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Monday, 1 April 2019 at 13:09:28 UTC, Dein wrote:
> > On Monday, 1 April 2019 at 01:18:44 UTC, Walter Bright wrote:
> >> On 3/31/2019 5:35 PM, Rubn wrote:
> >>> you can literally use it everywhere else you can use a type.
> >>
> >> No, you can't. An array of refs won't compile, either.
> >>
> >>   void test(int& a[]); // error
> >>
> >> A C++ ref can only appear at the top of a type AST, which is unlike any other type. Which exactly matches the only place a storage class can be!
> >
> > Seriously? You should know as well as I do what that function actually translates to:
> >
> >    void test(int&* const a);
> >
> > So I ask you now, how do you get a pointer to a reference. Its the exact same thing. Not sure if you are trying to just deceive me with some syntax sugar in C++ or what.
>
> Bad example, but the point stands:
>
>
> ----
> // foo.cpp
> int fun() {
>      int& foo[5]; // doesn't compile
> }
> ----
>
> I'd never even thought of it until Walter mentioned it that one can't have an array of references. Huh.

You could totally invent language where that was possible though, and it would be *awesome*!
April 04, 2019
On Mon, Apr 1, 2019 at 4:25 PM Guillaume Piolat via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Friday, 29 March 2019 at 16:06:09 UTC, Victor Porton wrote:
> > That `ref T` (where T is a type) is not a type is a serious
> > design error,
>
> No.
>
> > It is a very serious problem.
>
> No.
>
> > Can the language be changed to resolve this problem?
>
> There is no reason to do so.

I hope I've made my case... again.
April 04, 2019
On Tue, Apr 2, 2019 at 4:10 AM Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 4/2/19 4:11 AM, Walter Bright wrote:
> > On 4/1/2019 5:55 PM, Atila Neves wrote:
> >> Factually incorrect.
> >
> > I suspect Rubn has confused the syntactical conflation of arrays with pointers in C, and the implicit coercion of arrays to pointers, as them being the same. They simply aren't the same, as they are semantically separated by one level of indirection.
>
> You forgot to mention that top-level "const" is ignored in function parameters (for the signature and mangling but not the implementation).

Actually, it's sadly not ignored, and MSVC mangles it! It's been a
massive PITA when writing some of the STL bindings in druntime!
I've had to manually build mangled function names to extern, because I
can't express it in D >_<

https://github.com/dlang/druntime/blob/master/src/core/stdcpp/allocator.d#L50
 <- you're loving it!
April 04, 2019
On 4/4/19 4:33 AM, Manu wrote:
> On Tue, Apr 2, 2019 at 4:10 AM Andrei Alexandrescu via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>>
>> On 4/2/19 4:11 AM, Walter Bright wrote:
>>> On 4/1/2019 5:55 PM, Atila Neves wrote:
>>>> Factually incorrect.
>>>
>>> I suspect Rubn has confused the syntactical conflation of arrays with
>>> pointers in C, and the implicit coercion of arrays to pointers, as them
>>> being the same. They simply aren't the same, as they are semantically
>>> separated by one level of indirection.
>>
>> You forgot to mention that top-level "const" is ignored in function
>> parameters (for the signature and mangling but not the implementation).
> 
> Actually, it's sadly not ignored, and MSVC mangles it!

I'd be surprised. It would be a gross bug. It didn't in 2004 when I still was using it. Herb advocates using top-level const in implementation, pointing out that it's ignored in the signature.

> It's been a
> massive PITA when writing some of the STL bindings in druntime!
> I've had to manually build mangled function names to extern, because I
> can't express it in D >_<
> 
> https://github.com/dlang/druntime/blob/master/src/core/stdcpp/allocator.d#L50
>   <- you're loving it!

Could that be a "pointer to const"? That's not top-level.

April 04, 2019
On 4/4/19 4:28 AM, Manu wrote:
> On Mon, Apr 1, 2019 at 4:25 PM Guillaume Piolat via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>>
>> On Friday, 29 March 2019 at 16:06:09 UTC, Victor Porton wrote:
>>> That `ref T` (where T is a type) is not a type is a serious
>>> design error,
>>
>> No.
>>
>>> It is a very serious problem.
>>
>> No.
>>
>>> Can the language be changed to resolve this problem?
>>
>> There is no reason to do so.
> 
> I hope I've made my case... again.

It's a problem we don't have a clear vision in the community on at least the obvious matters. Reference types are recognized even within C++ as ho-hum. These debates are also a time-waster, collectively and cumulatively many hours have been spent on this and of course nobody "got convinced" of anything.

There are many areas that are positively in need of and receptive to improvement. If only that enthusiasm was channeled that direction...