July 25, 2018
On Wednesday, 25 July 2018 at 02:21:18 UTC, Marco Leise wrote:
> Am Sat, 21 Jul 2018 19:22:05 +0000
> schrieb 12345swordy <alexanderheistermann@gmail.com>:
>
>> On Saturday, 21 July 2018 at 08:55:59 UTC, Paolo Invernizzi wrote:
>> 
>> > Frankly speaking, my feeling is that D is becoming a horrible mess for the programmer...
>> 
>> > /Paolo
>> How!? Please Explain. You need to demonstrate evidence instead of appeal to emotional fallacy by resorting to "feels".
>> 
>> -Alexander
>
> The DIP increases consistency recalling that rvalues are accepted:
>
> - for the implicit 'this' parameter in methods
> - in foreach loop variables declared as ref
>
> No more special rules: rvalues are implicitly promoted to
> lvalues where needed.

That's correct, but 'this' is already a special guest in C++ style PL, with its own special rules. The support for ref variable in foreach loop.... can be removed (yup!), or made stricter.. no more inconsistency.

> The feeling probably comes from the
> inevitable realization that the community is pluralistic and
> Dlang acquired a lot of features that go towards someone else's
> vision for a good PL. Some want a relaxed stance towards
> breaking change, some want C++ or ObjC compatibility, some
> want to know what assembly a piece of code compiles to or have
> soft realtime constraints that don't work with a system
> language's mark&sweep GC. Is D2 messier than D1? Sure it is,
> and it caters to more use cases, too. As soon as you
> substantiate what exact feature is adding to the horrible
> mess, someone (often a group) will jump to defend it, because
> they have a good use case or two.

Yep, and I'm conscious to be often a pessimistic, lurking guy here in the forum... :-/

> It is kind of ironic that in order to do better than C++ you
> have to support most of what modern C++ compilers offer and end
> up having tons of unrelated features that make the language
> just as bloated as C++ after a decade of community feedback.
> It is a system PL. I think it needs to be this way and is a
> lot cleaner with basic data types and more expressive still,
> lacking a lot of C++'s legacy.

There's a tension between Walter effort in turning D as a suitable language for memory correctness, and a good candidate for writing 'bug free rock solid software fast' and the continuous addition of features like this.

Joke aside, I'm still on Jonathan side on this.

Finally, sorry to use often the term 'feeling', and sorry for not being constructive: but really is a 'feeling'... I don't pretend to be right. So no problems in just ignoring that

 :-P

Cheers,
Paolo

July 25, 2018
On Wed., 25 Jul. 2018, 12:30 am Paolo Invernizzi via Digitalmars-d, < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 25 July 2018 at 02:21:18 UTC, Marco Leise wrote:
> > Am Sat, 21 Jul 2018 19:22:05 +0000
> > schrieb 12345swordy <alexanderheistermann@gmail.com>:
> >
> >> On Saturday, 21 July 2018 at 08:55:59 UTC, Paolo Invernizzi wrote:
> >>
> >> > Frankly speaking, my feeling is that D is becoming a horrible mess for the programmer...
> >>
> >> > /Paolo
> >> How!? Please Explain. You need to demonstrate evidence instead of appeal to emotional fallacy by resorting to "feels".
> >>
> >> -Alexander
> >
> > The DIP increases consistency recalling that rvalues are accepted:
> >
> > - for the implicit 'this' parameter in methods
> > - in foreach loop variables declared as ref
> >
> > No more special rules: rvalues are implicitly promoted to lvalues where needed.
>
> That's correct, but 'this' is already a special guest in C++ style PL, with its own special rules. The support for ref variable in foreach loop.... can be removed (yup!), or made stricter.. no more inconsistency.
>

With UFCS as a super popular feature of D, 'this' is not really much of a
special guest at all.
It's just as much the first argument of a function as the first argument of
*any* UFCS call.


> It is kind of ironic that in order to do better than C++ you
> > have to support most of what modern C++ compilers offer and end up having tons of unrelated features that make the language just as bloated as C++ after a decade of community feedback. It is a system PL. I think it needs to be this way and is a lot cleaner with basic data types and more expressive still, lacking a lot of C++'s legacy.
>
> There's a tension between Walter effort in turning D as a suitable language for memory correctness, and a good candidate for writing 'bug free rock solid software fast' and the continuous addition of features like this.
>

This isn't 'a feature' so much as lifting a restriction for the sake of a
bunch of uniformity and simplification.
I can't really see how you can find that disagreeable from your apparent
position...


Joke aside, I'm still on Jonathan side on this.
>
> Finally, sorry to use often the term 'feeling', and sorry for not being constructive: but really is a 'feeling'... I don't pretend to be right. So no problems in just ignoring that
>

It upsets me when people present strong opinions about this who literally have no horse in the race. This is only really meaningful, and only affects you if it actually affects you... It's clearly not important to you, or you wouldn't be basing your opinion on *I kinda feel...*

Jonathan's argument is similar. He's worried about something that this
thread has tried and failed to determine exactly what is.
Meanwhile I think we have determined that the presumed practical trouble
cases are even less that I suspected up front.


July 25, 2018
On Saturday, 21 July 2018 at 08:59:39 UTC, Manu wrote:
> On Sat, 21 Jul 2018 at 00:15, Johannes Loher via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Saturday, 21 July 2018 at 05:59:37 UTC, Manu wrote:
>> > [...]
>>
>> Let me give a concrete example of one of the situations Jonathan is describing. Consider the following code:

[Snip]

>>
>> Do you think this example in contrived? If yes, why?

[Snip]

> There are countless ways you can construct the same bug. ref doesn't
> contact this problem in a general way, so a solution to this class of
> problem shouldn't be ref's responsibility.

[Snip]

>
> ... I don't understand how the existing rule can be so zealously defended in the face of a
> bunch of advantages, when all other constructions of the exact same
> problem are silently allowed, and literally nobody complains about them ever!

+1000

Very well and elegantly argued Manu.

I also notice that nobody that opposes this DIP has bothered to address the inconsistency that you raised above, i.e. the current acceptance of the same behaviour in other constructions, but somehow oppose this DIP for the exact same behaviour.




July 25, 2018
On Saturday, 21 July 2018 at 01:17:40 UTC, Jonathan M Davis wrote:
> On Friday, July 20, 2018 18:04:26 Manu via Digitalmars-d wrote:
>> On Fri, 20 Jul 2018 at 18:02, Manu <turkeyman@gmail.com> wrote:
>> > [...]
>> >
>> > I think you're describing now a bug where a function returns an lvalue, but it was meant to return an rvalue.
>>
>> Sorry, wrong way around! I meant to say:
>> I think you're describing now a bug where a function returns an
>> rvalue, but it was meant to return an lvalue (ie, a ref).
>
> The function returning an rvalue isn't necessarily a bug. It's the fact that it was then used in conjunction with a function that accepts its argument by ref in order to mutate it. If a function accepts its argument by ref in order to mutate it, then it's a but for it to be given an rvalue regardless of whether the rvalue comes from. It's just that some cases are more obviously wrong than others (e.g. passing foo + bad might be obviously wrong, whereas passing foo.bar may be wrong but look correct).
>
> - Jonathan M Davis

If the value returned by the function is not supposed to be mutable, then the fact that the function taking the ref parameter doesn't mutate it is not a bug. If it is supposed to be mutable, then there's an unrelated bug in the function that returns the value, which just happens to get caught by the current ref parameter restriction. The only other sort of bug is where you have a value that isn't supposed to be mutated and you have no intention of mutating it, and yet you pass it to a ref function parameter the express purpose of which is to mutate it, and then you don't use the result of that mutation ... but it's hard to even see that as a bug, just a pointless exercise, and it's hard to come up with a likely scenario where this would happen accidentally.

The situation is similar with a property that either isn't supposed to be mutable and you don't expect to mutate it and don't use its changed value yet pass it to a ref parameter the express purpose of which is to mutate it, or the property is supposed to be mutable but isn't and the current ref parameter restriction just happens to catch that unrelated bug.

I've read this exchange carefully and so far I agree with Manu's reasoning and the value of the DIP as it stands, and I'm not in favor of requiring @rvalue, as that negates much of the intent. However, I'm a D neophyte so I could well be missing something.

July 25, 2018
On Wednesday, 25 July 2018 at 08:34:30 UTC, Manu wrote:
[snip]

> It upsets me when people present strong opinions about this who literally have no horse in the race. This is only really meaningful, and only affects you if it actually affects you... It's clearly not important to you, or you wouldn't be basing your opinion on *I kinda feel...*
>
> Jonathan's argument is similar. He's worried about something that this
> thread has tried and failed to determine exactly what is.

I don't think that's fair. He has been quite specific about his concern and the kind of situations where there would be degraded behavior, and it clearly *is* important to him, and he certainly has a horse in the race. But I believe you are correct that those are cases where there's some unrelated bug that the ref parameter restriction just happens to catch, and that's not a good enough argument for keeping the restriction.

> Meanwhile I think we have determined that the presumed practical trouble
> cases are even less that I suspected up front.

That's surprising; I didn't realize that you suspected practical trouble cases.

July 25, 2018
On Wednesday, 25 July 2018 at 08:34:30 UTC, Manu wrote:

> With UFCS as a super popular feature of D, 'this' is not really much of a
> special guest at all.
> It's just as much the first argument of a function as the first argument of
> *any* UFCS call.

Guido van Rossum has raised an objection on that a couple of decades ago...

>> There's a tension between Walter effort in turning D as a suitable language for memory correctness, and a good candidate for writing 'bug free rock solid software fast' and the continuous addition of features like this.
>>
>
> This isn't 'a feature' so much as lifting a restriction for the sake of a
> bunch of uniformity and simplification.
> I can't really see how you can find that disagreeable from your apparent position...

That proposal is a 'Syntactic Sugar' feature, that simply hide what normally need to be explicitly coded: proved a temp rvalue, pass it to a callable taking ref. What you call 'simplification', I call it 'obfuscation'; what you call uniformity I call trying to spread a well justified restriction...

>> Finally, sorry to use often the term 'feeling', and sorry for not being constructive: but really is a 'feeling'... I don't pretend to be right. So no problems in just ignoring that
>>
>
> It upsets me when people present strong opinions about this who literally have no horse in the race. This is only really meaningful, and only affects you if it actually affects you... It's clearly not important to you, or you wouldn't be basing your opinion on *I kinda feel...*
>
> Jonathan's argument is similar. He's worried about something that this
> thread has tried and failed to determine exactly what is.
> Meanwhile I think we have determined that the presumed practical trouble cases are even less that I suspected up front.

Experience, in programming, has value: Walter is famous for his anecdotes on that.

D2 has already a lot of problematic stuff to solve, I not buy adding more (yes) features for the sake of an hypothetical 'simplification' of what it's already possibile.

Just to be clear, I'm also against all the new proposed addition for, named parameter, new struct initialisation and so on....

No pun, really :-P

/Paolo


July 26, 2018
On 26/07/2018 12:40 AM, Paolo Invernizzi wrote:
> Just to be clear, I'm also against all the new proposed addition for, named parameter, new struct initialisation and so on....

You'll go giddy once you hear about what I have planned after named parameters ;)

But seriously tho, just because a pattern of code can be done purely in library, doesn't mean it can't be done entirely better with a nice simple language feature which makes it considerably easier to learn and understand.

We do have to be careful, that we only try to go after features which are fairly well proven to our existing code and not for a theoretical improvement.
July 25, 2018
On Wednesday, 25 July 2018 at 12:40:16 UTC, Paolo Invernizzi wrote:

> That proposal is a 'Syntactic Sugar' feature, that simply hide what normally need to be explicitly coded: proved a temp rvalue, pass it to a callable taking ref. What you call 'simplification', I call it 'obfuscation'; what you call uniformity I call trying to spread a well justified restriction...
> /Paolo

A restriction which causes pointless redundant code for the caller who doesn't always have source code access. If my old teacher assistant taught me anything it is this: Redundant code is bad. You are literately forcing the programmer to create tmp variables that risk the possibility of being shadowed or worse, having its value change.

Your manual solution suggestion have it own set of problems. You might as well argue against the foreach statement, because its "obfuscation".

-Alexander
July 25, 2018
On Wednesday, 25 July 2018 at 13:36:38 UTC, 12345swordy wrote:
> On Wednesday, 25 July 2018 at 12:40:16 UTC, Paolo Invernizzi wrote:
>
>> That proposal is a 'Syntactic Sugar' feature, that simply hide what normally need to be explicitly coded: proved a temp rvalue, pass it to a callable taking ref. What you call 'simplification', I call it 'obfuscation'; what you call uniformity I call trying to spread a well justified restriction...
>> /Paolo
>
> A restriction which causes pointless redundant code for the caller who doesn't always have source code access. If my old teacher assistant taught me anything it is this: Redundant code is bad. You are literately forcing the programmer to create tmp variables that risk the possibility of being shadowed or worse, having its value change.

That's an opinion, naturally.

What it's "pointless redundant" for you, it is let's "let's force the programmer to think about what he is doing, passing an rvalue by ref" for me, at least.

At best, is "let's catch early some bugs (caused by other problems as Manu pointed out)", but as Jonathan states.

> Your manual solution suggestion have it own set of problems.

Set of problems as automatic promotion or conversion, as decades of problems with unsigned/signed have proved...

> You might as well argue against the foreach statement, because its "obfuscation"

There's not a magic conversion between apples and oranges in a foreach loop... ref value apart.

/Paolo



July 25, 2018
On Saturday, 21 July 2018 at 08:59:39 UTC, Manu wrote:
> On Sat, 21 Jul 2018 at 00:15, Johannes Loher via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Saturday, 21 July 2018 at 05:59:37 UTC, Manu wrote:
>> > [...]
>>
>> Let me give a concrete example of one of the situations Jonathan is describing. Consider the following code:
>>
>>
>> struct Secret
>> {
>> public:
>>      string key;
>> }
>>
>> /* ... */
>>
>> genrateRandomKey(ref string key) {
>>      key = /*  some code to actually generate the key */
>> }
>>
>> Secret secret;
>> generateRandomKey(secret.key);
>>
>>
>> Now somebody else working on the project who sees the definition of Secret might think "Having public access to member variables is bad, so lets use property methods instead. This even allows us to do some contract checks!" and he changes the definition of Secret to the following:
>>
>>
>> struct Secret
>> {
>> private:
>>      string _key;
>>
>> public:
>>      string key() @property const
>>      {
>>          return this._key;
>>      }
>>
>>      void key(string key) @property
>>      in
>>      {
>>          assert(key.length == 256)
>>      }
>>      do
>>      {
>>          this._key = key;
>>      }
>> }
>>
>>
>> Now with DIP 1016, the use of generateRandomKey silently "fails", i.e. secret._key will not be changed by it, which in this case is a big problem as the key is still default initialized!
>>
>> Of course one might argue that genrateRandomKey should not take its argument by reference and rather just return the key instead. But in my experience, there is quite a lot of code like this out there (e.g. in order to avoid copying, string is probably not the best example here...).
>>
>> In one of your earlier answers you argued, that in cases like this, the @property function should probably have returned by reference and that not doing so is the real bug. Do you also think this is true in this case? I don't think so. One reason is for example, that you can not put contracts on your setter @property method then...
>>
>> In my opinion, there is no bug with the definition of the @property methods here. The bug only arises through interactions with functions which take its parameters by reference.
>>
>> Do you think this example in contrived? If yes, why?
>
> So, to be clear; the 'gotcha' moment as proposed is this:
>   1. Function mutates an input received by ref.
>   2. Existing code is structured so the function is called with a
> member of some lvalue.
>   3. Member is _changed_ to be an accessor property for some reason
> *and* the property returns the value by-val.
>   4. Gotcha!
>
> It is definitely pretty contrived.
>
> 1. The function in this scenario is clearly an 'out' parameter, so it
> should use 'out', not ref.
> 2. A function like that would almost certainly return its result, not
> mutate an argument. Using ref this way is a poor choice and subverts
> move semantics.
> 3. Scenario depends on introduction of a getter, but any getter
> property that returns a member by-val is almost certainly a primitive
> type. A getter for a struct member would necessarily return a ref, or
> it would experience large copy semantics every time the get is called!

This is assuming anything that isn't a primitive is a large struct that is copied, which, in my experience, is rarely the case.

I don't recall ever implementing a getter in D that returns by ref. I'd consider that a code smell in pretty much every language, allowing mutation from the outside. For context, I think that getters are a faint code smell and that setters always stink.

All of this to say that I disagree that getters will usually return by ref unless the return type is a primitive. That's not how I write code and I don't remember encountering this in the wild.

> 4. A struct-type getter that returns by-val exhibits this gotcha in a
> variety of ways; you 'get' the member (a by-val copy), then mutate a
> member in any way, (ie, call a method), and you've accidentally
> modified the copy, not the source value!

I have trouble understanding why anyone would expect to mutate the original object without first consulting the API to see if was returned by ref. I'd never expect that to happen. I don't think that's a bug because I'd never expect things to work that way. Nearly all of my variables and function parameters are const anyway. Maybe my brain is weird. All I know is that I'd never encounter this and consider it a bug. To me not mutating my object is a feature.

> (`ref` is not the bug)
>   - note, in all other constructions of this same 'bug', existing
> language semantics find it acceptable to silently accept the
> accidental mutation of an expiring rvalue. Nobody is losing sleep at
> night.

That's because T().mutate() is obviously not going to do anything. Nobody would expect it to.

> The same 'bug' expressed in a simpler and more likely way:
>
> // a struct that shall be the member
> struct M {
>   int x;
>   void mutate() { ++x; }
> }
>
> // the original (working) code
> struct S {
>   M member;
> }
> S s;
> s.member.mutate();

It'd take roughly 5s between me seeing this in code review and typing the words "Law of Demeter violation". To me that's TRWTF.

> ...all that said, we understand that there is value in inhibiting calls with rvalues in some cases. We address this in a very nice way with @disable, which is also nicely symmetrical such that the limitation may by applied to rval or lval's.

I like using @disable this way. It's unclear to me the impact on existing code that doesn't already have a @disable since it wasn't needed before.

I'm not against the DIP - I think easier interop with C++ is a good thing and this would help it. I have to think a bit more about the points Jonathan has brought up, because it sounds like there's a possibility that bugs might be introduced if the DIP goes through, at least as-is. I'm not sure.

Atila