www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Who wore it better?

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I grepped phobos for "inout" and picked a heavy one. Not even cherry 
picking here. You be the judges.

Before:

inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure nothrow
{
     alias U = inout(T);
     static U* max(U* a, U* b) nothrow { return a > b ? a : b; }
     static U* min(U* a, U* b) nothrow { return a < b ? a : b; }

     auto b = max(r1.ptr, r2.ptr);
     auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
     return b < e ? b[0 .. e - b] : null;
}

After:

auto overlap(T, U)(T[] r1, U[] r2)  trusted pure nothrow
if (is(typeof(r1.ptr < r2.ptr) == bool))
{
     import std.algorithm : min, max;
     auto b = max(r1.ptr, r2.ptr);
     auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
     return b < e ? b[0 .. e - b] : null;
}

Who wore it better?


Andrei
Apr 15 2016
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
https://github.com/D-Programming-Language/phobos/pull/4201 -- Andrei
Apr 15 2016
parent reply Namespace <rswhite4 gmail.com> writes:
Since it is a template: Why these attributes:  trusted pure 
nothrow ?
Apr 15 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 01:31 PM, Namespace wrote:
 Since it is a template: Why these attributes:  trusted pure nothrow ?
trusted is not inferrable, the others are type-independent and nice for the documentation. -- Andrei
Apr 15 2016
parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Friday, April 15, 2016 13:46:24 Andrei Alexandrescu via Digitalmars-d 
wrote:
 On 04/15/2016 01:31 PM, Namespace wrote:
 Since it is a template: Why these attributes:  trusted pure nothrow ?
trusted is not inferrable, the others are type-independent and nice for the documentation. -- Andrei
Yes. I definitely think that it should be standard policy in Phobos (if not D code in general) to only use attribute inference when it's actually required. Without attribute inference, attributes and templates really wouldn't work together (which is why we have it), but the cost is that you don't know what the actual attributes are without compiling the code. So, while some folks may not like the extra typing, I think that it's clearly better for everyone who has to look at or maintain a function and/or its documentation to know what its attributes are by looking just at it, even if it's a little bit of extra work for the person who writes the function initially. I honestly wish that we hadn't added attribute inference to auto return functions, since I think that it's just enabling a bad practice. - Jonathan M Davis
Apr 15 2016
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/15/16 1:24 PM, Andrei Alexandrescu wrote:
 I grepped phobos for "inout" and picked a heavy one. Not even cherry
 picking here. You be the judges.

 Before:

 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure nothrow
 {
      alias U = inout(T);
      static U* max(U* a, U* b) nothrow { return a > b ? a : b; }
      static U* min(U* a, U* b) nothrow { return a < b ? a : b; }

      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }

 After:

 auto overlap(T, U)(T[] r1, U[] r2)  trusted pure nothrow
 if (is(typeof(r1.ptr < r2.ptr) == bool))
 {
      import std.algorithm : min, max;
      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }

 Who wore it better?
inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) trusted pure nothrow { import std.algorithm: min, max; auto b = max(r1.ptr, r2.ptr); auto e = min(r1.ptr + r1.length, r2.ptr + r2.length); return b < e ? b[0 .. e - b] : null; } -Steve
Apr 15 2016
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 On 4/15/16 1:24 PM, Andrei Alexandrescu wrote:
 I grepped phobos for "inout" and picked a heavy one. Not even cherry
 picking here. You be the judges.

 Before:

 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure nothrow
 {
      alias U = inout(T);
      static U* max(U* a, U* b) nothrow { return a > b ? a : b; }
      static U* min(U* a, U* b) nothrow { return a < b ? a : b; }

      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }

 After:

 auto overlap(T, U)(T[] r1, U[] r2)  trusted pure nothrow
 if (is(typeof(r1.ptr < r2.ptr) == bool))
 {
      import std.algorithm : min, max;
      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }

 Who wore it better?
inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) trusted pure nothrow { import std.algorithm: min, max; auto b = max(r1.ptr, r2.ptr); auto e = min(r1.ptr + r1.length, r2.ptr + r2.length); return b < e ? b[0 .. e - b] : null; }
Is that better or worse than the one without inout? -- Andrei
Apr 15 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/15/16 2:48 PM, Andrei Alexandrescu wrote:
 On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure nothrow
 {
      import std.algorithm: min, max;
      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }
Is that better or worse than the one without inout? -- Andrei
Better. It generates one implementation for all 9 combinations of mutability. Yours generates 9 identical binary functions. And yours possibly depends on a bug: https://issues.dlang.org/show_bug.cgi?id=15930 -Steve
Apr 15 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 03:13 PM, Steven Schveighoffer wrote:
 On 4/15/16 2:48 PM, Andrei Alexandrescu wrote:
 On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure
 nothrow
 {
      import std.algorithm: min, max;
      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }
Is that better or worse than the one without inout? -- Andrei
Better. It generates one implementation for all 9 combinations of mutability. Yours generates 9 identical binary functions.
A valid but weak argument. There's been long talk about eliminating binary identical functions in the front end (some linkers already do it). That would be the real solution that would help cases unrelated to inout, too.
 And yours possibly depends on a bug:
 https://issues.dlang.org/show_bug.cgi?id=15930
Red herring. Fixing the bug shouldn't break that code. Andrei
Apr 15 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/15/16 4:05 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 03:13 PM, Steven Schveighoffer wrote:
 On 4/15/16 2:48 PM, Andrei Alexandrescu wrote:
 On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted pure
 nothrow
 {
      import std.algorithm: min, max;
      auto b = max(r1.ptr, r2.ptr);
      auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }
Is that better or worse than the one without inout? -- Andrei
Better. It generates one implementation for all 9 combinations of mutability. Yours generates 9 identical binary functions.
A valid but weak argument. There's been long talk about eliminating binary identical functions in the front end (some linkers already do it). That would be the real solution that would help cases unrelated to inout, too.
The main argument is this: auto overlap(T, U)(T[] r1, U[] r2) trusted pure nothrow Can you tell, does overlap modify any data in r1 or r2? If you find such advertisement useless, you of course do not need inout or const.
 And yours possibly depends on a bug:
 https://issues.dlang.org/show_bug.cgi?id=15930
Red herring. Fixing the bug shouldn't break that code.
I don't know what the bug is. That's why I said "possibly." I was surprised your code compiled with both const/mutable parameters, but then I found the bug. It's possible it could be fixed and become correct. I'm not sure. -Steve
Apr 15 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 04:16 PM, Steven Schveighoffer wrote:
 If you find such advertisement useless, you of course do not need inout
 or const.
Let's not exaggerate by putting them together. -- Andrei
Apr 15 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/15/16 4:34 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:16 PM, Steven Schveighoffer wrote:
 If you find such advertisement useless, you of course do not need inout
 or const.
Let's not exaggerate by putting them together. -- Andrei
This is not an exaggeration. inout and const have pretty much the same benefits and drawbacks, with only a couple of major differences. The main feature of const/inout is advertisement of non-mutation. Otherwise, we could do with just mutable and immutable + templates. -Steve
Apr 15 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 04:45 PM, Steven Schveighoffer wrote:
 On 4/15/16 4:34 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:16 PM, Steven Schveighoffer wrote:
 If you find such advertisement useless, you of course do not need inout
 or const.
Let's not exaggerate by putting them together. -- Andrei
This is not an exaggeration.
Jesus. C++ has const without inout. We used to have const without inout - and we probably should again. -- Andrei
Apr 15 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/15/16 5:01 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:45 PM, Steven Schveighoffer wrote:
 On 4/15/16 4:34 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:16 PM, Steven Schveighoffer wrote:
 If you find such advertisement useless, you of course do not need inout
 or const.
Let's not exaggerate by putting them together. -- Andrei
This is not an exaggeration.
Jesus. C++ has const without inout. We used to have const without inout - and we probably should again. -- Andrei
"C++ has it" is a terrible argument. If you care about advertisement, you can't use templates to advertise whether something is const or not. Your solution is "let's use templates instead". That works, but obviously, compiler will let you molest whatever data you want. Then advertisement is done with documentation and trust. C++ simply doesn't have that capability to advertise const for the things inout can, but also const isn't as restrictive in C++, so you can put const on things that aren't really const. IIRC Walter says C++ const is useless for guarantees (and I agree with that). Tell me what the benefits of const are. Pretty much all the arguments you are saying for getting rid of inout (that don't involve corner cases we can fix) can be used to say we should get rid of const too. Why stop getting rid of complexity at inout? -Steve
Apr 15 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 05:27 PM, Steven Schveighoffer wrote:
 On 4/15/16 5:01 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:45 PM, Steven Schveighoffer wrote:
 On 4/15/16 4:34 PM, Andrei Alexandrescu wrote:
 On 04/15/2016 04:16 PM, Steven Schveighoffer wrote:
 If you find such advertisement useless, you of course do not need
 inout
 or const.
Let's not exaggerate by putting them together. -- Andrei
This is not an exaggeration.
Jesus. C++ has const without inout. We used to have const without inout - and we probably should again. -- Andrei
"C++ has it" is a terrible argument.
You're losing track of the thread of the argument. It's not an argument, it's the factual correct refutation of your wrong claim.
 If you care about advertisement, you can't use templates to advertise
 whether something is const or not. Your solution is "let's use templates
 instead". That works, but obviously, compiler will let you molest
 whatever data you want. Then advertisement is done with documentation
 and trust.

 C++ simply doesn't have that capability to advertise const for the
 things inout can, but also const isn't as restrictive in C++, so you can
 put const on things that aren't really const. IIRC Walter says C++ const
 is useless for guarantees (and I agree with that).

 Tell me what the benefits of const are. Pretty much all the arguments
 you are saying for getting rid of inout (that don't involve corner cases
 we can fix) can be used to say we should get rid of const too. Why stop
 getting rid of complexity at inout?
The simple answer is const pays enough, inout doesn't. Anyhow this meandering is the kiss of death - this exchange is becoming a time-wasting back and forth, exactly the kind I promised myself to not get involved in. I'll keep your good points in mind when deciding whether we should rid D of inout. Thanks, Andrei
Apr 15 2016
prev sibling parent Kagamin <spam here.lot> writes:
On Friday, 15 April 2016 at 21:01:44 UTC, Andrei Alexandrescu 
wrote:
 Jesus. C++ has const without inout. We used to have const 
 without inout - and we probably should again. -- Andrei
What about immutability? E.g. Java gets away with immutable in a library and it just werks.
Apr 18 2016
prev sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 15 Apr 2016 14:48:26 -0400
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 On 4/15/16 1:24 PM, Andrei Alexandrescu wrote: =20
 auto overlap(T, U)(T[] r1, U[] r2)  trusted pure nothrow
 if (is(typeof(r1.ptr < r2.ptr) =3D=3D bool))
 {
      import std.algorithm : min, max;
      auto b =3D max(r1.ptr, r2.ptr);
      auto e =3D min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 }

 Who wore it better? =20
inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) trusted pure nothr=
ow
 {
      import std.algorithm: min, max;
      auto b =3D max(r1.ptr, r2.ptr);
      auto e =3D min(r1.ptr + r1.length, r2.ptr + r2.length);
      return b < e ? b[0 .. e - b] : null;
 } =20
=20 Is that better or worse than the one without inout? -- Andrei
=20 I tend to write functions in the latter style, to avoid unneeded template instantiations. In this case it also documents the intent better. Both arrays are of the same type T and we wont modify the contents. Even if the compiler can remove binary identical instances after the fact, the compile time and memory use increases. It also has implications on debugging. After duplicate removal, you cannot map a function address to a unique symbol name any more. Just my 2=C2=A2. --=20 Marco
Apr 15 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 04/15/2016 04:47 PM, Marco Leise wrote:
 Am Fri, 15 Apr 2016 14:48:26 -0400
 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 4/15/16 2:46 PM, Steven Schveighoffer wrote:
 On 4/15/16 1:24 PM, Andrei Alexandrescu wrote:
 auto overlap(T, U)(T[] r1, U[] r2)  trusted pure nothrow
 if (is(typeof(r1.ptr < r2.ptr) == bool))
 {
       import std.algorithm : min, max;
       auto b = max(r1.ptr, r2.ptr);
       auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
       return b < e ? b[0 .. e - b] : null;
 }

 Who wore it better?
inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) trusted pure nothrow { import std.algorithm: min, max; auto b = max(r1.ptr, r2.ptr); auto e = min(r1.ptr + r1.length, r2.ptr + r2.length); return b < e ? b[0 .. e - b] : null; }
Is that better or worse than the one without inout? -- Andrei
I tend to write functions in the latter style, to avoid unneeded template instantiations. In this case it also documents the intent better. Both arrays are of the same type T and we wont modify the contents.
Thanks, this is a good point that needs keeping in mind.
 Even if the compiler can remove binary identical instances
 after the fact, the compile time and memory use increases.
 It also has implications on debugging. After duplicate
 removal, you cannot map a function address to a unique symbol
 name any more.
This is perhaps weaker. Andrei
Apr 15 2016
prev sibling parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Friday, 15 April 2016 at 18:46:01 UTC, Steven Schveighoffer 
wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)
Might be nice if inout applied to template parameter types: T[] overlap(inout T)(T[] r1, T[] r2); If it wasn't for the virtual function issue, I wonder if inout would still be needed on runtime arguments given the above feature? Using traits like CopyConstness might be enough.
Apr 24 2016
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/24/16 6:40 AM, Nick Treleaven wrote:
 On Friday, 15 April 2016 at 18:46:01 UTC, Steven Schveighoffer wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)
Might be nice if inout applied to template parameter types: T[] overlap(inout T)(T[] r1, T[] r2); If it wasn't for the virtual function issue, I wonder if inout would still be needed on runtime arguments given the above feature?
The only issue is that overlap being passed a mutable T[] could modify the data. This is the major deficiency with the template solution. As I've said before, if you don't care about advertisement of non-mutation, then inout doesn't really do much for you. -Steve
Apr 25 2016
prev sibling parent Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Friday, 15 April 2016 at 17:24:19 UTC, Andrei Alexandrescu 
wrote:
 inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2)  trusted
BTW, why is overlap undocumented - is ctfe support a good enough reason? https://github.com/dlang/phobos/blob/v2.071.0/std/array.d#L715 I've thought about implementing something similar, good to know it's there. I wonder if there are places in Phobos that could use this. Also, its unittest needs to get undocumented too, it's appearing in the previous symbol's documentation instead.
Apr 17 2016