Re: So what does (inout int = 0) do?

2016-05-02 Thread Steven Schveighoffer via Digitalmars-d

On 5/1/16 7:58 PM, Seb wrote:

On Friday, 15 April 2016 at 23:05:14 UTC, Steven Schveighoffer wrote:

On 4/15/16 6:31 PM, Timon Gehr wrote:

[...]


I'm sorry, should have put on my standard disclaimer that I am not a
compiler writer :) I actually have no idea how this is done in the
compiler, just how a compiler should behave as I understand it in my
head.

[...]


inout(bool) newsgroup.revive_discussion();

can we make the compiler smart enough to solve the use-cases of inout
(=auto const/immutable deducation)?


If we can find a way to replace inout with something that does 
effectively everything inout does, then I'm all for it.


-Steve


Re: So what does (inout int = 0) do?

2016-05-01 Thread Seb via Digitalmars-d
On Friday, 15 April 2016 at 23:05:14 UTC, Steven Schveighoffer 
wrote:

On 4/15/16 6:31 PM, Timon Gehr wrote:

[...]


I'm sorry, should have put on my standard disclaimer that I am 
not a compiler writer :) I actually have no idea how this is 
done in the compiler, just how a compiler should behave as I 
understand it in my head.


[...]


inout(bool) newsgroup.revive_discussion();

can we make the compiler smart enough to solve the use-cases of 
inout (=auto const/immutable deducation)?


Re: So what does (inout int = 0) do?

2016-04-19 Thread Kagamin via Digitalmars-d

On Monday, 18 April 2016 at 00:53:26 UTC, Temtaime wrote:

shared currently is useless too tbw


shared did catch bugs in phobos and user code, that would 
otherwise sneak in.


Re: So what does (inout int = 0) do?

2016-04-19 Thread Kagamin via Digitalmars-d

On Sunday, 17 April 2016 at 17:39:48 UTC, QAston wrote:
First @property + compiler switch, now @property + deprecated 
switch. When should I use property? For all the getters? Should 
I start with property or with member access? Does it even 
matter because of optional parens? Why do I even need to care 
about this?


Rationale behind DIP23 seems to make language usable without 
@property and provide a puristic feature for those who are into 
it and for one corner case.


Re: So what does (inout int = 0) do?

2016-04-18 Thread Adam D. Ruppe via Digitalmars-d

On Monday, 18 April 2016 at 08:53:31 UTC, Guillaume Piolat wrote:

And shared and @property :)


I still want to see @property fixed rather than removed - the 
edge case with returning a delegate is an interesting one to me 
(though that's ALL I want it to do, leave everything else alone)


Re: So what does (inout int = 0) do?

2016-04-18 Thread Marc Schütz via Digitalmars-d

On Saturday, 16 April 2016 at 11:49:21 UTC, Nick Treleaven wrote:

On 16/04/2016 12:40, Marc Schütz wrote:
What are the plans for DIP25's `return` attribute? Because 
with it, the
compiler has enough information to know that the return value 
aliases `s`:


const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, 
in T[]

replacement);

If the function is passed a mutable `s`, its return value can 
be

implicitly convertible to `T[]`.


AIUI, functions don't have to return part of the parameter 
tagged with return, it can return anything.


See:
http://wiki.dlang.org/DIP25#Types_of_Result_vs._Parameters


I'm not sure. That section says that the situation may change in 
the future. Other parts of the DIP can be read both ways, but it 
doesn't mention aliasing explicitly. As this is currently still 
experimental and not a complete design anyway, we can change it 
to fit our needs.


Re: So what does (inout int = 0) do?

2016-04-18 Thread Guillaume Piolat via Digitalmars-d

On Monday, 18 April 2016 at 08:52:19 UTC, Guillaume Piolat wrote:
Personnally I wish synchronized, comma operator, and actively 
harmful things would go. nothrow provides little value, but no 
negative value.


And shared and @property :)
But I guess this isn't Christmas already.



Re: So what does (inout int = 0) do?

2016-04-18 Thread Guillaume Piolat via Digitalmars-d

On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:

On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:

On 17.04.2016 18:44, Nick Treleaven wrote:

I think @property is OK.


No, it isn't:



Seriously, @property is one of the biggest SNAFUs of the 
language.


I think I'll write an editorial about this stuff in TWID 
tonight. (I'm also very skeptical of the value of pure, @safe, 
nothrow, and @nogc)


As a big user of @nogc, I'd disagree. @nogc is a bit hard to use 
and effectively split the language in two, but gives the absolute 
confidence that nothing will block.


In audio callbacks and you are supposed to use tryLock and 
atomics instead of locking, so allocating is a big problem. And 
it's very easy to let something passthrough like a rogue closure 
or an array literal.


@nogc is a big safety net I thought wasn't needed, until I had to 
make @nogc code.


Personnally I wish synchronized, comma operator, and actively 
harmful things would go. nothrow provides little value, but no 
negative value.


Re: So what does (inout int = 0) do?

2016-04-17 Thread deadalnix via Digitalmars-d

On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:

On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:

On 17.04.2016 18:44, Nick Treleaven wrote:

I think @property is OK.


No, it isn't:



Seriously, @property is one of the biggest SNAFUs of the 
language.




Today I learned a new acronym. Fit @property perfectly.



Re: So what does (inout int = 0) do?

2016-04-17 Thread Temtaime via Digitalmars-d

On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:

On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:

On 17.04.2016 18:44, Nick Treleaven wrote:

I think @property is OK.


No, it isn't:



Seriously, @property is one of the biggest SNAFUs of the 
language.


I think I'll write an editorial about this stuff in TWID 
tonight. (I'm also very skeptical of the value of pure, @safe, 
nothrow, and @nogc)


nothrow may be useful for passing callbacks in C functions.
shared currently is useless too tbw


Re: So what does (inout int = 0) do?

2016-04-17 Thread Adam D. Ruppe via Digitalmars-d

On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:

On 17.04.2016 18:44, Nick Treleaven wrote:

I think @property is OK.


No, it isn't:



Seriously, @property is one of the biggest SNAFUs of the language.

I think I'll write an editorial about this stuff in TWID tonight. 
(I'm also very skeptical of the value of pure, @safe, nothrow, 
and @nogc)


Re: So what does (inout int = 0) do?

2016-04-17 Thread Timon Gehr via Digitalmars-d

On 17.04.2016 18:44, Nick Treleaven wrote:

I think @property is OK.


No, it isn't:

import std.stdio;
struct S{
@property int delegate() foo(){ return ()=>3; }
}

void main(){
S s;
writeln(s.foo()); // "int delegate()"
}



Re: So what does (inout int = 0) do?

2016-04-17 Thread ag0aep6g via Digitalmars-d

On 17.04.2016 19:39, QAston wrote:

First @property + compiler switch, now @property + deprecated switch.
When should I use property? For all the getters? Should I start with
property or with member access? Does it even matter because of optional
parens? Why do I even need to care about this?


@property is in a bad state right now. The behavior that used to be 
enabled by -property has been decided against, and now @property has 
only one effect that I can think of off the top of my head, and it's 
rather subtle:



int foo() {return 0;}
@property int bar() {return 0;}

pragma(msg, typeof(foo)); /* int() */
pragma(msg, typeof(bar)); /* int */

pragma(msg, typeof(&foo)); /* int function() ref */
pragma(msg, typeof(&bar)); /* int function() @property ref */


I don't think anyone is really happy with the current @property, but 
everyone is probably tired of discussing it.


Re: So what does (inout int = 0) do?

2016-04-17 Thread QAston via Digitalmars-d

On Sunday, 17 April 2016 at 16:44:50 UTC, Nick Treleaven wrote:
The @safe troika is a good design (except @safe should be the 
default), the implementation is lacking though. Ideallists want 
to make @safe strict now, but break code sometimes even without 
basic workarounds for memory-safe code. Pragmatists want to 
avoid breakage but make the subset of @safe code wider, making 
the definition more complex. There seems to be a stalemate.


Yeah, but for example rust deals with the same problem with a 
single keyword.


scope, if implemented for reference types, wouldn't scale well. 
It should be the default, with __escape meaning scope(false). I 
think it's an uphill battle arguing for this, but it is crucial 
to avoiding GC without runtime checks. At least for non-GC code 
in a general way.


scope (for function parameters) cannot be implemented in 
backwards compatible way because a lot of code uses in (which is 
const^scope)


I think @property is OK. I think the controversy at the time 
was about optional brackets in function calls, which is 
different.
First @property + compiler switch, now @property + deprecated 
switch. When should I use property? For all the getters? Should I 
start with property or with member access? Does it even matter 
because of optional parens? Why do I even need to care about this?


Sure all of the things I've mentioned can be defended. The 
question is not whether they have a usecase (because all of them 
do), but whether return on investment for them is good enough and 
how they interact with the rest of the language.


CTFE does what you'd expect it to do - constant folding is 
intuitive and requires little to no code changes. Purity is 
orthogonal to the rest of the language (modulo corner cases) and 
enables some patterns for immutable value creation. Those (and 
others - the stuff that's good doesn't come to mind because it 
works) have higher ROI and aren't as much of a burden for library 
writers.


Re: So what does (inout int = 0) do?

2016-04-17 Thread Nick Treleaven via Digitalmars-d

On Sunday, 17 April 2016 at 14:30:59 UTC, QAston wrote:
You've got lucky with pure (modulo corner cases) and ctfe, much 
less lucky with @safe, @trusted, @system, inout, shared, scope, 
property.


The @safe troika is a good design (except @safe should be the 
default), the implementation is lacking though. Ideallists want 
to make @safe strict now, but break code sometimes even without 
basic workarounds for memory-safe code. Pragmatists want to avoid 
breakage but make the subset of @safe code wider, making the 
definition more complex. There seems to be a stalemate.


scope, if implemented for reference types, wouldn't scale well. 
It should be the default, with __escape meaning scope(false). I 
think it's an uphill battle arguing for this, but it is crucial 
to avoiding GC without runtime checks. At least for non-GC code 
in a general way.


I think @property is OK. I think the controversy at the time was 
about optional brackets in function calls, which is different.


Re: So what does (inout int = 0) do?

2016-04-17 Thread QAston via Digitalmars-d
On Friday, 15 April 2016 at 20:03:07 UTC, Andrei Alexandrescu 
wrote:
We should really do away with the cowboy style of designing 
language, which sadly Walter and I have been guilty of too 
often in the past. The slow but sure accretion of complexity of 
inout is a textbook example of where that leads.


Andrei


This deserves to be a poster with a golden frame. You've got 
lucky with pure (modulo corner cases) and ctfe, much less lucky 
with @safe, @trusted, @system, inout, shared, scope, property.




Re: So what does (inout int = 0) do?

2016-04-16 Thread Lass Safin via Digitalmars-d

On Saturday, 16 April 2016 at 22:06:10 UTC, Marco Leise wrote:

Am Fri, 15 Apr 2016 09:44:05 -0400
schrieb Andrei Alexandrescu :

inout must go. -- Andrei

Ceterum censeo Carthaginem esse delendam. -- Marcus Porcius Cato
:o)


What does that have to do with what he said?
Are you comparing him to Cato?


Re: So what does (inout int = 0) do?

2016-04-16 Thread Marco Leise via Digitalmars-d
Am Fri, 15 Apr 2016 09:44:05 -0400
schrieb Andrei Alexandrescu :

inout must go. -- Andrei
 
Ceterum censeo Carthaginem esse delendam. -- Marcus Porcius Cato
:o)

-- 
Marco



Re: So what does (inout int = 0) do?

2016-04-16 Thread Nick Treleaven via Digitalmars-d

On 16/04/2016 12:40, Marc Schütz wrote:

What are the plans for DIP25's `return` attribute? Because with it, the
compiler has enough information to know that the return value aliases `s`:

const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, in T[]
replacement);

If the function is passed a mutable `s`, its return value can be
implicitly convertible to `T[]`.


AIUI, functions don't have to return part of the parameter tagged with 
return, it can return anything.


See:
http://wiki.dlang.org/DIP25#Types_of_Result_vs._Parameters


Re: So what does (inout int = 0) do?

2016-04-16 Thread Marc Schütz via Digitalmars-d

(It seems my reply got lost somewhere, reposting...)

On Friday, 15 April 2016 at 19:28:02 UTC, Andrei Alexandrescu 
wrote:
A better support for this argument is std.array.replaceSlice at 
https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594:


inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] 
replacement);


So here we are guaranteed that (a) the result type is the same 
as the first argument, and (b) the first argument is never 
modified even if a mutable slice is passed.


What are the plans for DIP25's `return` attribute? Because with 
it, the compiler has enough information to know that the return 
value aliases `s`:


const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, in 
T[] replacement);


If the function is passed a mutable `s`, its return value can be 
implicitly convertible to `T[]`.


Re: So what does (inout int = 0) do?

2016-04-16 Thread Jacob Carlborg via Digitalmars-d

On 2016-04-15 07:38, Andrei Alexandrescu wrote:


I think we should deprecate inout. For real. It costs way too much for
what it does. For all I can tell most of D's proponents don't know how
it works. -- Andrei


If "inout" is only used as a way avoid code duplication, both when 
writing the code and the compiler generating the code. Then that can be 
solved with two steps:


1. Improve the compiler to remove duplicated functions overloaded on 
constness. That is, they generate the exact same code and and the only 
difference is the constness of the functions. This is a useful 
improvement regardless


2. Write a string mixin that duplicates a function three times, one for 
each type of constness:


// Assuming "inout" is removed from the language and not a keyword anymore

mixin(inout(q{
inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] 
replacement) { ... }

});

The "input" function would need to parse arbitrary D code and create 
three version of the passed in function declaration, mutable, const and 
immutable. In theory libdparse could be used for this but it doesn't 
work at compile time. The downside is that it looks really ugly when 
defining an inout function.


But, with AST macros it could look like this:

@inout inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] 
replacement);


--
/Jacob Carlborg


Re: So what does (inout int = 0) do?

2016-04-16 Thread Nick Treleaven via Digitalmars-d

On 15/04/2016 04:10, Andrei Alexandrescu wrote:

Commenting it out yields a number of unittest compilation errors,
neither informative about the root of the problem and indicative as to
how the parameter solves it.

...

2. There needs to be documentation for people working on the standard
library so they don't need to waste time on their own discovery process.


Perhaps use this, at least for now:

// 
alias InOutParam = inout int;

...
(InOutParam)
{
...
}

It's less cryptic at the use-site and people can lookup the definition 
to find an explanation.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 6:31 PM, Timon Gehr wrote:

On 15.04.2016 23:56, Steven Schveighoffer wrote:


Impossible or difficult to do with the current implementation?
...


What I'm saying is that the check that is currently implemented is not
adequate for the new case. This is not terribly important though. The
point was that there needs to be a design effort beyond lifting the
limitation, and you seemed to claim that the current implementation
already takes care of the presented issue, which is not the case.

Your ideas are sound though.


I'm sorry, should have put on my standard disclaimer that I am not a 
compiler writer :) I actually have no idea how this is done in the 
compiler, just how a compiler should behave as I understand it in my head.



I may have said this incorrectly. The language itself wouldn't really be
that much more complex. It's the cost of understanding what each of the
different inout pools mean.


They would just be named parameters to the function on the type system
level, similar to template arguments but not causing repeated
instantiation.


Right, but again: these are named by the writer of the template, not the 
language, right? In that case, any identifier becomes a modifier. Or are 
you thinking of something different?



The benefit would be quite small, whereas
there are obvious places inout makes sense -- the 'this' parameter and
the return value.
...


The return value might contain more than one pointer, and functions
often have more than one parameter.


Of course, but the transference of mutability from parameter to return 
value is the obvious draw of such a wildcard. In most cases, there is 
only one return value, and therefore only one pool that needs to be handled.


ref/out parameters can serve as alternate returns as well as composed types.

It's not that functions don't have multiple returns with their own 
inout, but I don't think it's very common. As we get more and more 
obscure, the cost/benefit ratio for complexity vs. power gets higher. 
And already people don't like where we are right now with it.



Then there is the syntax that would be required, I'm not sure what that
looks like.
...


Anything that is analogous to template parameters, e.g. an additional
set of arguments with a different delimiter. Many workable
possibilities. Anyway, it is unlikely to happen.


Especially given the discussion happening here, I agree.


Humans are creatures of habit and familiarity. To allow each library to
define what words mean what for modifiers would be really difficult to
deal with.



I don't see how the library would do that.


Just throwing a strawman out there:

void foo(bingo = inout, zingo = inout)(bingo(int)* x, zingo(int)* y)

So inside foo, bingo is one flavor of inout, zingo is another. This 
could vary library to library, function to function.


It would work, and be sound design. I would just hate it is all :)

Perhaps you have a better system in mind?

-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 23:56, Steven Schveighoffer wrote:

On 4/15/16 5:17 PM, Timon Gehr wrote:

On 15.04.2016 22:47, Steven Schveighoffer wrote:


There's no difference between a function that declares its variables
inout within its parameters or one that declares them locally.
...


Yes, there is. Semantic analysis sees the parameter types before it sees
the body.


I don't know what the current implementation sees the function as doing.
The way I look at it, the function context is like an extra parameter to
the inner function. If it contains inout data,


Rather, when the inout data is actually accessed.


then that needs to be
taken into account if the inner function has additional inout parameters.
...


That's sensible, of course. The current implementation is a lot more 
conservative though.



For example:

inout(int) *x;

inout(int) *foo(inout int) {return x;}

foo is really taking 2 parameters: y and the context pointer that
contains x. It almost looks like this:

inout(int) *foo(inout int, ref inout(int) *x) { return x;}

call this with: foo(1, x)

And it won't compile.

However, call it with: foo(inout(int)(1), x);

and it should be fine, returning an inout(int)*.




They should be treated the same once the function starts compiling.
...


I think I have stated clearly why this is impossible. :P


Impossible or difficult to do with the current implementation?
...


What I'm saying is that the check that is currently implemented is not 
adequate for the new case. This is not terribly important though. The 
point was that there needs to be a design effort beyond lifting the 
limitation, and you seemed to claim that the current implementation 
already takes care of the presented issue, which is not the case.


Your ideas are sound though.



At the point where we need to tag multiple pools of inout parameters,
the complexity of the language doesn't justify the benefits.
...


I think this is a funny place to draw the line, but I guess this is a
matter of taste.


I may have said this incorrectly. The language itself wouldn't really be
that much more complex. It's the cost of understanding what each of the
different inout pools mean.


They would just be named parameters to the function on the type system 
level, similar to template arguments but not causing repeated instantiation.



The benefit would be quite small, whereas
there are obvious places inout makes sense -- the 'this' parameter and
the return value.
...


The return value might contain more than one pointer, and functions 
often have more than one parameter.



Then there is the syntax that would be required, I'm not sure what that
looks like.
...


Anything that is analogous to template parameters, e.g. an additional 
set of arguments with a different delimiter. Many workable 
possibilities. Anyway, it is unlikely to happen.




We could make it possible, for instance, to templatize the mutability
modifier instead of using a specific keyword. Then you could have
foo(int)[]. Then I think you could do all this (and scrap inout), but I
wouldn't want to work in that language.


Well, that is precisely the way that languages with real type systems
address issues like this one. D has many others like it.


Aye, solutions like Rebindable, which is pretty much a failure IMO, show
how lack of expressiveness in the core language can't be easily
substituted.


Note that for type systems, complexity and expressiveness do not
necessarily correlate.


Humans are creatures of habit and familiarity. To allow each library to
define what words mean what for modifiers would be really difficult to
deal with.

-Steve


I don't see how the library would do that.




Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 5:17 PM, Timon Gehr wrote:

On 15.04.2016 22:47, Steven Schveighoffer wrote:


There's no difference between a function that declares its variables
inout within its parameters or one that declares them locally.
...


Yes, there is. Semantic analysis sees the parameter types before it sees
the body.


I don't know what the current implementation sees the function as doing. 
The way I look at it, the function context is like an extra parameter to 
the inner function. If it contains inout data, then that needs to be 
taken into account if the inner function has additional inout parameters.


For example:

inout(int) *x;

inout(int) *foo(inout int) {return x;}

foo is really taking 2 parameters: y and the context pointer that 
contains x. It almost looks like this:


inout(int) *foo(inout int, ref inout(int) *x) { return x;}

call this with: foo(1, x)

And it won't compile.

However, call it with: foo(inout(int)(1), x);

and it should be fine, returning an inout(int)*.




They should be treated the same once the function starts compiling.
...


I think I have stated clearly why this is impossible. :P


Impossible or difficult to do with the current implementation?


At the point where we need to tag multiple pools of inout parameters,
the complexity of the language doesn't justify the benefits.
...


I think this is a funny place to draw the line, but I guess this is a
matter of taste.


I may have said this incorrectly. The language itself wouldn't really be 
that much more complex. It's the cost of understanding what each of the 
different inout pools mean. The benefit would be quite small, whereas 
there are obvious places inout makes sense -- the 'this' parameter and 
the return value.


Then there is the syntax that would be required, I'm not sure what that 
looks like.



We could make it possible, for instance, to templatize the mutability
modifier instead of using a specific keyword. Then you could have
foo(int)[]. Then I think you could do all this (and scrap inout), but I
wouldn't want to work in that language.


Well, that is precisely the way that languages with real type systems
address issues like this one. D has many others like it.


Aye, solutions like Rebindable, which is pretty much a failure IMO, show 
how lack of expressiveness in the core language can't be easily substituted.



Note that for type systems, complexity and expressiveness do not
necessarily correlate.


Humans are creatures of habit and familiarity. To allow each library to 
define what words mean what for modifiers would be really difficult to 
deal with.


-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 23:03, Andrei Alexandrescu wrote:

On 04/15/2016 04:47 PM, Steven Schveighoffer wrote:

There's no difference between a function that declares its variables
inout within its parameters or one that declares them locally.


So now we get to things like:

void fun() {
   inout int ohHello = 42;
   ...
}

How to explain such a construct? Not to mention globals of that type are
not allowed.


Andrei



It's an int that has not decided yet whether it wants to be mutable, 
const or immutable and goes out of scope before it is able to make up 
its mind.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 05:17 PM, Timon Gehr wrote:

Well, that is precisely the way that languages with real type systems
address issues like this one. D has many others like it.

Note that for type systems, complexity and expressiveness do not
necessarily correlate.


Nicely put on both counts. (Well "real" is semantically sarcastic a 
bit.) I don't even disagree :o). -- Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 22:47, Steven Schveighoffer wrote:

On 4/15/16 4:27 PM, Timon Gehr wrote:

On 15.04.2016 22:03, Steven Schveighoffer wrote:

On 4/15/16 3:48 PM, Timon Gehr wrote:

On 15.04.2016 17:22, Steven Schveighoffer wrote:

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152







It works around a limitation of inout that isn't necessary (even
though
I thought it was being helpful when I suggested it). That is,
functions
without inout parameters cannot declare local inout variables. But
this
isn't really necessary, and should be fixed. I will discuss this in my
talk in a few weeks.
...


That's potentially dangerous. What about cases like the following?

void main(){
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a);
 int[] z=foo(b);
}


We don't need to guess:

void foo (inout int)
{
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a); // line 9
 int[] z=foo(b);  // line 10
}

testinout.d(9): Error: modify inout to immutable is not allowed inside
inout function
testinout.d(10): Error: modify inout to mutable is not allowed inside
inout function



I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758
main is not an inout function in the example above. I.e. if we just
change the compiler minimally such as to allow making inout local
variables, the above example will violate immutability guarantees. You
can also imagine cases where the inout local variable is defined only
after the local inout function has been declared and called with a
non-inout argument. At which point does the constraint become active?
etc. We cannot _simply_ allow declaring inout locals.


There's no difference between a function that declares its variables
inout within its parameters or one that declares them locally.
...


Yes, there is. Semantic analysis sees the parameter types before it sees 
the body.



They should be treated the same once the function starts compiling.
...


I think I have stated clearly why this is impossible. :P






Note, the =0 part isn't necessary right now, since it's not called.
It's
just used to test if the function can compile.

In short, my opinion on inout is that it has some unnecessary
limitations, which can be removed, and inout will work as mostly
expected. These requirements to work around the limitations will go
away.
...


Other important limitations of inout are e.g.:
- inout variables cannot be fields.


I have a way to make this work.


Without syntax changes?
Can the struct/class instances with inout fields be returned from the
enclosing inout function?


Yes, as long as inout is wrapping inout. We run into this currently with
inout functions that create local types. e.g. emplace.

Obviously inout cannot be unwrapped if it is typed on a field of a
struct or class. So the unwrapping has to result in inout.
...


Ok.


- There can be only one inout in scope.


This is not so much a problem I think.
...


I think it is. It's just not the prevalent limitation one runs in at the
moment. It will be more of a problem once functions can return structs
with inout fields. IMHO compositionality should be ensured for a
language feature from the start.


At the point where we need to tag multiple pools of inout parameters,
the complexity of the language doesn't justify the benefits.
...


I think this is a funny place to draw the line, but I guess this is a 
matter of taste.




We could make it possible, for instance, to templatize the mutability
modifier instead of using a specific keyword. Then you could have
foo(int)[]. Then I think you could do all this (and scrap inout), but I
wouldn't want to work in that language.

-Steve


Well, that is precisely the way that languages with real type systems 
address issues like this one. D has many others like it.


Note that for type systems, complexity and expressiveness do not 
necessarily correlate.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 04:47 PM, Steven Schveighoffer wrote:

There's no difference between a function that declares its variables
inout within its parameters or one that declares them locally.


So now we get to things like:

void fun() {
  inout int ohHello = 42;
  ...
}

How to explain such a construct? Not to mention globals of that type are 
not allowed.



Andrei



Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 4:27 PM, Timon Gehr wrote:

On 15.04.2016 22:03, Steven Schveighoffer wrote:

On 4/15/16 3:48 PM, Timon Gehr wrote:

On 15.04.2016 17:22, Steven Schveighoffer wrote:

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152






It works around a limitation of inout that isn't necessary (even though
I thought it was being helpful when I suggested it). That is, functions
without inout parameters cannot declare local inout variables. But this
isn't really necessary, and should be fixed. I will discuss this in my
talk in a few weeks.
...


That's potentially dangerous. What about cases like the following?

void main(){
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a);
 int[] z=foo(b);
}


We don't need to guess:

void foo (inout int)
{
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a); // line 9
 int[] z=foo(b);  // line 10
}

testinout.d(9): Error: modify inout to immutable is not allowed inside
inout function
testinout.d(10): Error: modify inout to mutable is not allowed inside
inout function



I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758
main is not an inout function in the example above. I.e. if we just
change the compiler minimally such as to allow making inout local
variables, the above example will violate immutability guarantees. You
can also imagine cases where the inout local variable is defined only
after the local inout function has been declared and called with a
non-inout argument. At which point does the constraint become active?
etc. We cannot _simply_ allow declaring inout locals.


There's no difference between a function that declares its variables 
inout within its parameters or one that declares them locally.


They should be treated the same once the function starts compiling.






Note, the =0 part isn't necessary right now, since it's not called.
It's
just used to test if the function can compile.

In short, my opinion on inout is that it has some unnecessary
limitations, which can be removed, and inout will work as mostly
expected. These requirements to work around the limitations will go
away.
...


Other important limitations of inout are e.g.:
- inout variables cannot be fields.


I have a way to make this work.


Without syntax changes?
Can the struct/class instances with inout fields be returned from the
enclosing inout function?


Yes, as long as inout is wrapping inout. We run into this currently with 
inout functions that create local types. e.g. emplace.


Obviously inout cannot be unwrapped if it is typed on a field of a 
struct or class. So the unwrapping has to result in inout.



- There can be only one inout in scope.


This is not so much a problem I think.
...


I think it is. It's just not the prevalent limitation one runs in at the
moment. It will be more of a problem once functions can return structs
with inout fields. IMHO compositionality should be ensured for a
language feature from the start.


At the point where we need to tag multiple pools of inout parameters, 
the complexity of the language doesn't justify the benefits.


We could make it possible, for instance, to templatize the mutability 
modifier instead of using a specific keyword. Then you could have 
foo(int)[]. Then I think you could do all this (and scrap inout), but I 
wouldn't want to work in that language.


-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 22:03, Steven Schveighoffer wrote:

On 4/15/16 3:48 PM, Timon Gehr wrote:

On 15.04.2016 17:22, Steven Schveighoffer wrote:

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152





It works around a limitation of inout that isn't necessary (even though
I thought it was being helpful when I suggested it). That is, functions
without inout parameters cannot declare local inout variables. But this
isn't really necessary, and should be fixed. I will discuss this in my
talk in a few weeks.
...


That's potentially dangerous. What about cases like the following?

void main(){
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a);
 int[] z=foo(b);
}


We don't need to guess:

void foo (inout int)
{
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a); // line 9
 int[] z=foo(b);  // line 10
}

testinout.d(9): Error: modify inout to immutable is not allowed inside
inout function
testinout.d(10): Error: modify inout to mutable is not allowed inside
inout function



I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758
main is not an inout function in the example above. I.e. if we just 
change the compiler minimally such as to allow making inout local 
variables, the above example will violate immutability guarantees. You 
can also imagine cases where the inout local variable is defined only 
after the local inout function has been declared and called with a 
non-inout argument. At which point does the constraint become active? 
etc. We cannot _simply_ allow declaring inout locals.







Note, the =0 part isn't necessary right now, since it's not called. It's
just used to test if the function can compile.

In short, my opinion on inout is that it has some unnecessary
limitations, which can be removed, and inout will work as mostly
expected. These requirements to work around the limitations will go
away.
...


Other important limitations of inout are e.g.:
- inout variables cannot be fields.


I have a way to make this work.


Without syntax changes?
Can the struct/class instances with inout fields be returned from the 
enclosing inout function?



This is actually the most major sticking
point in inout.
 The only correct thing is to keep is that globals/static variables
cannot be typed inout.


- There can be only one inout in scope.


This is not so much a problem I think.
...


I think it is. It's just not the prevalent limitation one runs in at the 
moment. It will be more of a problem once functions can return structs 
with inout fields. IMHO compositionality should be ensured for a 
language feature from the start.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 4:08 PM, Andrei Alexandrescu wrote:

On 04/15/2016 04:03 PM, Steven Schveighoffer wrote:

I have a way to make this work. This is actually the most major sticking
point in inout.

The only correct thing is to keep is that globals/static variables
cannot be typed inout.


Another special case? The only correct thing is to simplify the language
to everybody's benefit. -- Andrei



This is not a special case any more than disallowing access of shared 
data from a pure function is a special case.


In fact, you could allow inout variables as static or globals, but just 
couldn't copy them to local inout variables (except full value types).


The point is that between 2 different calls to inout, the wrapper means 
something different. A global/static persists between calls.


-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 4:03 PM, Andrei Alexandrescu wrote:

On 04/15/2016 03:44 PM, Steven Schveighoffer wrote:


I assure you, these limitations were self-imposed. I insisted on them,
without realizing that they would cause problems with generic code. I
thought they would be good "lint" detection.

https://issues.dlang.org/show_bug.cgi?id=3748


Problem is we could have other problems once we fix those. As you just
showed, it has already happened.


If you look at the core of what inout actually is (a type modifier 
placeholder), we can simplify how to think about it, and how to 
implement it. These "requirements" were just extra helpful things that 
would flag valid, but (naively assumed) pointless code. Turns out, 
templates generate lots of pointless code (that is typically optimized 
away in the type system or the optimizer).


I hope to make this clear in my talk at dconf.


We should really do away with the cowboy style of designing language,
which sadly Walter and I have been guilty of too often in the past. The
slow but sure accretion of complexity of inout is a textbook example of
where that leads.


I actually agree, someone with as little experience as I had should not 
have been listened to when making such a feature :)


If I could do it over again, I would still want this feature, but 
obviously, we could make sane simple rules for it. They are actually 
quite easy to understand.


-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 04:03 PM, Steven Schveighoffer wrote:

I have a way to make this work. This is actually the most major sticking
point in inout.

The only correct thing is to keep is that globals/static variables
cannot be typed inout.


Another special case? The only correct thing is to simplify the language 
to everybody's benefit. -- Andrei




Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 3:48 PM, Timon Gehr wrote:

On 15.04.2016 17:22, Steven Schveighoffer wrote:

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152




It works around a limitation of inout that isn't necessary (even though
I thought it was being helpful when I suggested it). That is, functions
without inout parameters cannot declare local inout variables. But this
isn't really necessary, and should be fixed. I will discuss this in my
talk in a few weeks.
...


That's potentially dangerous. What about cases like the following?

void main(){
 inout(int)[] x=[1,2,3];
 immutable(int) a;
 int b;
 inout(int)[] foo(inout int){
 return x;
 }
 immutable(int)[] y=foo(a);
 int[] z=foo(b);
}


We don't need to guess:

void foo (inout int)
{
inout(int)[] x=[1,2,3];
immutable(int) a;
int b;
inout(int)[] foo(inout int){
return x;
}
immutable(int)[] y=foo(a); // line 9
int[] z=foo(b);  // line 10
}

testinout.d(9): Error: modify inout to immutable is not allowed inside 
inout function
testinout.d(10): Error: modify inout to mutable is not allowed inside 
inout function







Note, the =0 part isn't necessary right now, since it's not called. It's
just used to test if the function can compile.

In short, my opinion on inout is that it has some unnecessary
limitations, which can be removed, and inout will work as mostly
expected. These requirements to work around the limitations will go away.
...


Other important limitations of inout are e.g.:
- inout variables cannot be fields.


I have a way to make this work. This is actually the most major sticking 
point in inout.


The only correct thing is to keep is that globals/static variables 
cannot be typed inout.



- There can be only one inout in scope.


This is not so much a problem I think.

-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 03:44 PM, Steven Schveighoffer wrote:

No, because it's not sound. you cannot cast to const through 2+
indirections. However inout works there.


That is correct, a classic... thanks for getting me straight.


I think the point of Kenji's argument is that inout's current
limitations are what you are bumping into, and those limitations are
unnecessary and arbitrary. We can make inout better and more consistent.
Pretty easily actually. We can certainly fix the inout int = 0 problem.


I'm not sure - at all in fact. This is at the tail of a sequence of
changes of inout, and there is a history of such mini-designs leading to
complications, regressions, and further mini-designs. It's the wolf that
eats the dog that eats the cat that eats the mouse. We fix this and
there's another and then another and then another. It has already
happened.


I assure you, these limitations were self-imposed. I insisted on them,
without realizing that they would cause problems with generic code. I
thought they would be good "lint" detection.

https://issues.dlang.org/show_bug.cgi?id=3748


Problem is we could have other problems once we fix those. As you just 
showed, it has already happened.


We should really do away with the cowboy style of designing language, 
which sadly Walter and I have been guilty of too often in the past. The 
slow but sure accretion of complexity of inout is a textbook example of 
where that leads.



Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 17:22, Steven Schveighoffer wrote:

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152



It works around a limitation of inout that isn't necessary (even though
I thought it was being helpful when I suggested it). That is, functions
without inout parameters cannot declare local inout variables. But this
isn't really necessary, and should be fixed. I will discuss this in my
talk in a few weeks.
...


That's potentially dangerous. What about cases like the following?

void main(){
inout(int)[] x=[1,2,3];
immutable(int) a;
int b;
inout(int)[] foo(inout int){
return x;
}
immutable(int)[] y=foo(a);
int[] z=foo(b);
}




Note, the =0 part isn't necessary right now, since it's not called. It's
just used to test if the function can compile.

In short, my opinion on inout is that it has some unnecessary
limitations, which can be removed, and inout will work as mostly
expected. These requirements to work around the limitations will go away.
...


Other important limitations of inout are e.g.:
- inout variables cannot be fields.
- There can be only one inout in scope.



I expect after reading this thread that the Q&A will be.. interesting.

-Steve





Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 3:28 PM, Andrei Alexandrescu wrote:

On 4/15/16 2:39 PM, Steven Schveighoffer wrote:

On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:


Would it be difficult to make it work without inout?


T[] dup(T)(T[] arr)

this should be doable. Problem is, you get identical instantiations for
each of the different qualifiers, unless you take different actions
based on the mutability. Instead:

inout(T)[] dup(T)(inout(T)[] arr)

This is one instantiation, no matter the mutability of the parameter.
And it guarantees no molestation of arr, even if it's mutable.

This would be much more difficult with a struct/class, whereas with
inout it's pretty simple.

But I think dup as it is defined is a bad example, because as defined by
the language, it implies that you want a mutable version where the
source may be const/immutable. In the general sense, a duplication
function where you get the *same* mutability is more applicable for
inout.


A better support for this argument is std.array.replaceSlice at
https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594:


inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement);

So here we are guaranteed that (a) the result type is the same as the
first argument, and (b) the first argument is never modified even if a
mutable slice is passed.


In fact, a mutable slice must be passed (slice is not marked as inout).



I agree this is a nice property, and one that C++ does not enjoy. The
questions are of course how important it is, how useful it is, and what
price it is worth.

Getting back to replaceSlice I'd define it in more flexible terms
anyway. So I'd eliminate the use of inout there even if it did add value.


You can add more flexibility and keep inout at the same time. The nice 
feature here is that inout protects the elements of s that aren't in 
slice, and there is no requirement to verify s and slice are the same 
underlying type, etc.



One thing to understand is that inout is only valuable if you think
const is valuable. That is, you think the advertisement of "no, I will
not modify this parameter, give me whatever you got" is of value. If you
don't care, then templates suffice.


This is correct but incomplete. The omitted part is that inout is
valuable when $EVERYTHING_YOU_SAID and also you want to transport the
qualifier from an argument to the result. This diminishes its importance
considerably for all folks, including those for whom const is important.


Nope. Actually inout has proven to have a more interesting property of 
not requiring casting.





void popFront(T)(inout(T)[] arr)


void popFront(T)(ref inout(T)[] arr);

(point stays)


Yes, thanks, that is what I meant.




This is possible only with inout. const will not cut it. The current
definition is:

void popFront(T)(T[] arr)

which is OK, but there is no advertisement that popFront doesn't change
any data in arr.


Should this work as well?

void popFront(ref const(T)[] arr);

In other words conversion of ref T[] to ref const(T)[] is sound.


No, because it's not sound. you cannot cast to const through 2+ 
indirections. However inout works there.



I think the point of Kenji's argument is that inout's current
limitations are what you are bumping into, and those limitations are
unnecessary and arbitrary. We can make inout better and more consistent.
Pretty easily actually. We can certainly fix the inout int = 0 problem.


I'm not sure - at all in fact. This is at the tail of a sequence of
changes of inout, and there is a history of such mini-designs leading to
complications, regressions, and further mini-designs. It's the wolf that
eats the dog that eats the cat that eats the mouse. We fix this and
there's another and then another and then another. It has already happened.


I assure you, these limitations were self-imposed. I insisted on them, 
without realizing that they would cause problems with generic code. I 
thought they would be good "lint" detection.


https://issues.dlang.org/show_bug.cgi?id=3748


In fact Walter's and my design of inout is a prime example of the
failings of that approach. We underdesigned it to work in a few small
examples. We knew we lost when Kenji figured inout must be a type
qualifier (we were hoping to getting away with it being a sort of a
placeholder/wildcard). I think we should have pulled it back then. It's
become a mini-monster that only wants more attention, more language
changes, more work.


It must be a type qualifier or it doesn't work.


An interesting thing is that when you involve generic code, certain
"good ideas" become very inconvenient. For example, this whole
discussion is based on the idea that "if you don't have any inout
parameters, why are you declaring inout variables? It makes no sense!" A
very sensible and logical idea. But when you want code that works with
or without inout variables, all of a sudden the same code is throwing an
error in some cases because of an unforeseen situation.


This is an

Re: So what does (inout int = 0) do?

2016-04-15 Thread Dmitry Olshansky via Digitalmars-d

On 15-Apr-2016 08:38, Andrei Alexandrescu wrote:

On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:

On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via
Digitalmars-d
wrote:

[snip]


- Jonathan M Davis


I think we should deprecate inout. For real. It costs way too much for
what it does. For all I can tell most of D's proponents don't know how
it works. -- Andrei


Love this trend! inout is a monstrously complicated feature solving 
minor inconvenience.


--
Dmitry Olshansky


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 4/15/16 2:39 PM, Steven Schveighoffer wrote:

On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:

On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:


Didn't you use array.dup until now? It's a good example to handle
qualifiers with inout.


Would it be difficult to make it work without inout?


T[] dup(T)(T[] arr)

this should be doable. Problem is, you get identical instantiations for
each of the different qualifiers, unless you take different actions
based on the mutability. Instead:

inout(T)[] dup(T)(inout(T)[] arr)

This is one instantiation, no matter the mutability of the parameter.
And it guarantees no molestation of arr, even if it's mutable.

This would be much more difficult with a struct/class, whereas with
inout it's pretty simple.

But I think dup as it is defined is a bad example, because as defined by
the language, it implies that you want a mutable version where the
source may be const/immutable. In the general sense, a duplication
function where you get the *same* mutability is more applicable for inout.


A better support for this argument is std.array.replaceSlice at 
https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594:


inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement);

So here we are guaranteed that (a) the result type is the same as the 
first argument, and (b) the first argument is never modified even if a 
mutable slice is passed.


I agree this is a nice property, and one that C++ does not enjoy. The 
questions are of course how important it is, how useful it is, and what 
price it is worth.


Getting back to replaceSlice I'd define it in more flexible terms 
anyway. So I'd eliminate the use of inout there even if it did add value.



It's not sensible at all, inout is already well-defined and has much
power in D's type system.
Removing it is just a foolish idea.


What are a few examples of the power of inout?


One thing to understand is that inout is only valuable if you think
const is valuable. That is, you think the advertisement of "no, I will
not modify this parameter, give me whatever you got" is of value. If you
don't care, then templates suffice.


This is correct but incomplete. The omitted part is that inout is 
valuable when $EVERYTHING_YOU_SAID and also you want to transport the 
qualifier from an argument to the result. This diminishes its importance 
considerably for all folks, including those for whom const is important.



void popFront(T)(inout(T)[] arr)


void popFront(T)(ref inout(T)[] arr);

(point stays)


This is possible only with inout. const will not cut it. The current
definition is:

void popFront(T)(T[] arr)

which is OK, but there is no advertisement that popFront doesn't change
any data in arr.


Should this work as well?

void popFront(ref const(T)[] arr);

In other words conversion of ref T[] to ref const(T)[] is sound.


What things does inout afford us, that would be otherwise not achievable?


advertisement of const without having to cast the type to const (and all
the limitations that entail).


If you worry the future of Phobos written in D, first you would need to
think about @safe.
It's yet not well defined/implemented by compiler, and many Phobos code
are marked as @trusted.
Does it has lower priority than complain to a small hack for the
*current* inout limitation?


The thing about @safe is it does enable things that otherwise would not
be possible. Overall I agree there are plenty of things that deserve a
revisit, but just putting in competition things against one another is
unlikely to shed light on their technical merit.


I think the point of Kenji's argument is that inout's current
limitations are what you are bumping into, and those limitations are
unnecessary and arbitrary. We can make inout better and more consistent.
Pretty easily actually. We can certainly fix the inout int = 0 problem.


I'm not sure - at all in fact. This is at the tail of a sequence of 
changes of inout, and there is a history of such mini-designs leading to 
complications, regressions, and further mini-designs. It's the wolf that 
eats the dog that eats the cat that eats the mouse. We fix this and 
there's another and then another and then another. It has already happened.


In fact Walter's and my design of inout is a prime example of the 
failings of that approach. We underdesigned it to work in a few small 
examples. We knew we lost when Kenji figured inout must be a type 
qualifier (we were hoping to getting away with it being a sort of a 
placeholder/wildcard). I think we should have pulled it back then. It's 
become a mini-monster that only wants more attention, more language 
changes, more work.



An interesting thing is that when you involve generic code, certain
"good ideas" become very inconvenient. For example, this whole
discussion is based on the idea that "if you don't have any inout
parameters, why are you declaring inout variables? It makes no sense!" A
very sensible and logica

Re: So what does (inout int = 0) do?

2016-04-15 Thread deadalnix via Digitalmars-d

On Friday, 15 April 2016 at 12:54:11 UTC, ixid wrote:
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu 
wrote:
We want Phobos to be beautiful, a prime example of good D 
code. Admittedly, it also needs to be very general and 
efficient, which sometimes gets in the way. But we cannot 
afford an accumulation of mad tricks to obscure the large 
design.



Andrei


Why didn't we go with all functions being able to infer const, 
pure etc rather than just templates?


The problem is essentially untractable when there are loops in 
the call graph.


That being said, it would make sense to do it for auto functions.



Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:

On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:


Didn't you use array.dup until now? It's a good example to handle
qualifiers with inout.


Would it be difficult to make it work without inout?


T[] dup(T)(T[] arr)

this should be doable. Problem is, you get identical instantiations for 
each of the different qualifiers, unless you take different actions 
based on the mutability. Instead:


inout(T)[] dup(T)(inout(T)[] arr)

This is one instantiation, no matter the mutability of the parameter. 
And it guarantees no molestation of arr, even if it's mutable.


This would be much more difficult with a struct/class, whereas with 
inout it's pretty simple.


But I think dup as it is defined is a bad example, because as defined by 
the language, it implies that you want a mutable version where the 
source may be const/immutable. In the general sense, a duplication 
function where you get the *same* mutability is more applicable for inout.



It's not sensible at all, inout is already well-defined and has much
power in D's type system.
Removing it is just a foolish idea.


What are a few examples of the power of inout?


One thing to understand is that inout is only valuable if you think 
const is valuable. That is, you think the advertisement of "no, I will 
not modify this parameter, give me whatever you got" is of value. If you 
don't care, then templates suffice.


void popFront(T)(inout(T)[] arr)

This is possible only with inout. const will not cut it. The current 
definition is:


void popFront(T)(T[] arr)

which is OK, but there is no advertisement that popFront doesn't change 
any data in arr.



What things does inout afford us, that would be otherwise not achievable?


advertisement of const without having to cast the type to const (and all 
the limitations that entail).



If you worry the future of Phobos written in D, first you would need to
think about @safe.
It's yet not well defined/implemented by compiler, and many Phobos code
are marked as @trusted.
Does it has lower priority than complain to a small hack for the
*current* inout limitation?


The thing about @safe is it does enable things that otherwise would not
be possible. Overall I agree there are plenty of things that deserve a
revisit, but just putting in competition things against one another is
unlikely to shed light on their technical merit.


I think the point of Kenji's argument is that inout's current 
limitations are what you are bumping into, and those limitations are 
unnecessary and arbitrary. We can make inout better and more consistent. 
Pretty easily actually. We can certainly fix the inout int = 0 problem.



To restate my arguments:

1. The motivation of inout is clear and simple - have it as a
placeholder for any other qualifier so as to avoid the method
duplication observed in C++. However, it has over time grown into a
feature of which complexity way transcends its small usefulness.


It has some rough edges. These can be smoothed out.


2. Attempting to make inout useful have created their own problems,
solving which in turn have increased its complexity. This cycle of
accretions has led over time to a vortex of oddity in the middle of the
type system.


This is not what you are railing against. The current limitations (and 
their workarounds) are self-imposed, we just need to get rid of them.


An interesting thing is that when you involve generic code, certain 
"good ideas" become very inconvenient. For example, this whole 
discussion is based on the idea that "if you don't have any inout 
parameters, why are you declaring inout variables? It makes no sense!" A 
very sensible and logical idea. But when you want code that works with 
or without inout variables, all of a sudden the same code is throwing an 
error in some cases because of an unforeseen situation.


Another example is code like this:

int firstInt(T...)(T t)
{
  foreach(ref x; t)
  {
  static if(typeof(x) == int)
 return x;
  }
  return -1;
}

This throws an error because if there is an int in T..., then return -1 
statement is "unreachable". This is similar to the inout int = 0 case. 
In non-generic code, it makes sense to flag code that won't be reached. 
But in generic code, it's actually not a true statement for all 
instantiations of the template! It's another limitation we should relax.



3. For all problems that inout is purported to solve, I know of idioms
that are definitely simpler and overall almost as good if not better. So
a hard question is whether the existence is justified.


I know of no "better" idioms, in terms of code generation and 
specificity, to replace inout (or at least, inout as I envision it 
should be). Care to elaborate?


-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 02:24 PM, jmh530 wrote:

I had not realized that the main reason that inout was added was because
of not being able to use templates as virtual functions in classes.


The main reason is actually avoiding code duplication is such situations 
(i.e. the problem has a solution just not ideal). -- Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread jmh530 via Digitalmars-d
On Friday, 15 April 2016 at 17:11:39 UTC, Andrei Alexandrescu 
wrote:


3. For all problems that inout is purported to solve, I know of 
idioms that are definitely simpler and overall almost as good 
if not better. So a hard question is whether the existence is 
justified.


If it's something to be avoided except in particular cases, then 
I suggest that is made clear in the documentation. I had not 
realized that the main reason that inout was added was because of 
not being able to use templates as virtual functions in classes.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:


Didn't you use array.dup until now? It's a good example to handle
qualifiers with inout.


Would it be difficult to make it work without inout?


It's not sensible at all, inout is already well-defined and has much
power in D's type system.
Removing it is just a foolish idea.


What are a few examples of the power of inout?

What things does inout afford us, that would be otherwise not achievable?


If you worry the future of Phobos written in D, first you would need to
think about @safe.
It's yet not well defined/implemented by compiler, and many Phobos code
are marked as @trusted.
Does it has lower priority than complain to a small hack for the
*current* inout limitation?


The thing about @safe is it does enable things that otherwise would not 
be possible. Overall I agree there are plenty of things that deserve a 
revisit, but just putting in competition things against one another is 
unlikely to shed light on their technical merit.



I just cannot agree your argument.


I understand and would like to be better informed. So could you please 
substantiate your argument by replying to the questions above?


To restate my arguments:

1. The motivation of inout is clear and simple - have it as a 
placeholder for any other qualifier so as to avoid the method 
duplication observed in C++. However, it has over time grown into a 
feature of which complexity way transcends its small usefulness.


2. Attempting to make inout useful have created their own problems, 
solving which in turn have increased its complexity. This cycle of 
accretions has led over time to a vortex of oddity in the middle of the 
type system.


3. For all problems that inout is purported to solve, I know of idioms 
that are definitely simpler and overall almost as good if not better. So 
a hard question is whether the existence is justified.


There are 306 uses of inout in Phobos. A good thing to do would be an 
investigation of their usefulness.



Andrei



Re: So what does (inout int = 0) do?

2016-04-15 Thread Kenji Hara via Digitalmars-d
2016-04-15 22:41 GMT+09:00 Andrei Alexandrescu via Digitalmars-d <
digitalmars-d@puremagic.com>:

> On 04/15/2016 06:50 AM, Kenji Hara via Digitalmars-d wrote:
>
>>
>>
>> You should recall the history of inout.
>> http://wiki.dlang.org/DIP2
>>
>> At first, It has designed to temporarily squash mutable/const/immutable
>> qualifiers on function argument inside function body. Therefore when
>> inout qualifier appears in function return type, but doesn't on
>> parameter types, we defined it an error.
>>
>> However, I concluded that we can remove the restriction. When an inout
>> object arises from thin air, no one holds the qualifier of its real
>> instance. It means, the returned inout object can be converted to
>> arbitrary qualifiers without type system breaking.
>>
>> Two years ago I opened an enhancement issue:
>> https://issues.dlang.org/show_bug.cgi?id=13006
>>
>> And posted a pull request.
>> https://github.com/D-Programming-Language/dmd/pull/3740
>>
>
> I do recall the history. The enhancement is sensible in a frame of mind
> "we need to keep inout" but I'm looking at top level and thinking, crap we
> can put up with a little duplication if we get rid of inout. It's just a
> prime example of apparently simple idea gone bonkers.
>
> In all of my recent code I've avoided inout and didn't miss it one bit.
> There's no need for it - I replace it with one-liners that forward to
> template functions, which in turn deduce qualifiers and all is great.


Didn't you use array.dup until now? It's a good example to handle
qualifiers with inout.
It's not sensible at all, inout is already well-defined and has much power
in D's type system.
Removing it is just a foolish idea.

If you worry the future of Phobos written in D, first you would need to
think about @safe.
It's yet not well defined/implemented by compiler, and many Phobos code are
marked as @trusted.
Does it has lower priority than complain to a small hack for the *current*
inout limitation?

I just cannot agree your argument.

Kenji Hara


Re: So what does (inout int = 0) do?

2016-04-15 Thread Steven Schveighoffer via Digitalmars-d

On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152


It works around a limitation of inout that isn't necessary (even though 
I thought it was being helpful when I suggested it). That is, functions 
without inout parameters cannot declare local inout variables. But this 
isn't really necessary, and should be fixed. I will discuss this in my 
talk in a few weeks.


Note, the =0 part isn't necessary right now, since it's not called. It's 
just used to test if the function can compile.


In short, my opinion on inout is that it has some unnecessary 
limitations, which can be removed, and inout will work as mostly 
expected. These requirements to work around the limitations will go away.


I expect after reading this thread that the Q&A will be.. interesting.

-Steve


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 02:15 AM, Vladimir Panteleev wrote:

On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu wrote:

I think we should deprecate inout. For real. It costs way too much for
what it does. For all I can tell most of D's proponents don't know how
it works. -- Andrei


What would replace it in the case of classes, where you can't have
templated virtual methods? Perhaps a mechanism to declare a templated
virtual function, and a list of instantiations which will go into the
vtable?


You write several one-liners that forward to an internal template 
implementation.



If we are to kill inout and replace it with something else, then it
should support cases where inout failed, such as inout on the parameter
of a delegate passed to the function (see: inout opApply).


I think we should kill it, period. No replacement is really needed, for 
the most part most problems with inout are complications caused by the 
very presence of inout.


C++ has no parameterization of qualifiers and lived with it like a guy 
lives with a bald spot on a butt cheek. There's not even a proposal I 
can remember to fix that. Those duplications are the least of C++'s, or 
any langauge's, problems.


inout must go.


Andrei



Re: So what does (inout int = 0) do?

2016-04-15 Thread Guillaume Piolat via Digitalmars-d

On Friday, 15 April 2016 at 12:54:11 UTC, ixid wrote:


Why didn't we go with all functions being able to infer const, 
pure etc rather than just templates?


Non-templated function may not have their source code available. 
For consistency, non-template function have no inference.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 02:40 AM, Shammah Chancellor wrote:

I think that behavioral type checks are common enough in D that it
should have it's own first-class syntax.


No. -- Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 02:49 AM, Walter Bright wrote:

On 4/14/2016 8:10 PM, Andrei Alexandrescu wrote:

Commenting it out yields a number of unittest compilation errors, neither
informative about the root of the problem and indicative as to how the
parameter
solves it.


https://issues.dlang.org/show_bug.cgi?id=15926


Nice, thanks. I think I can put a finger on what bothers me the most: 
adding that "inout int = 0" to make code work cannot be an acceptable 
solution to any problem. So the fact that the problem exists is the 
actual problem. It's basic sense and sensibility in engineering. -- Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 03:42 AM, deadalnix wrote:

On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:

IIRC, the problem has to do with ranges of inout elements working
correctly, which gets really funky, because inout is a temporary thing
and not a full-on type constructor/qualifier. I believe that Kenji is
the one that implemented the fix, and I think that he explained it in
the newsgroup at some point. Certainly, there have been a few times
that it's come up in D.Learn when folks ask what the heck it is, so
there should be a few posts floating around with an explanation. This
is the only useful post that I could find in a quick search though:



Whatever the problem is, none of this seems like a good solution.


I agree. -- Andrei



Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 06:50 AM, Kenji Hara via Digitalmars-d wrote:



You should recall the history of inout.
http://wiki.dlang.org/DIP2

At first, It has designed to temporarily squash mutable/const/immutable
qualifiers on function argument inside function body. Therefore when
inout qualifier appears in function return type, but doesn't on
parameter types, we defined it an error.

However, I concluded that we can remove the restriction. When an inout
object arises from thin air, no one holds the qualifier of its real
instance. It means, the returned inout object can be converted to
arbitrary qualifiers without type system breaking.

Two years ago I opened an enhancement issue:
https://issues.dlang.org/show_bug.cgi?id=13006

And posted a pull request.
https://github.com/D-Programming-Language/dmd/pull/3740


I do recall the history. The enhancement is sensible in a frame of mind 
"we need to keep inout" but I'm looking at top level and thinking, crap 
we can put up with a little duplication if we get rid of inout. It's 
just a prime example of apparently simple idea gone bonkers.


In all of my recent code I've avoided inout and didn't miss it one bit. 
There's no need for it - I replace it with one-liners that forward to 
template functions, which in turn deduce qualifiers and all is great.


Andrei


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 05:07 AM, Timon Gehr wrote:

The fundamental problem is that inout is disallows certain kinds of
composition. It's a flawed language primitive.


I agree. The more I try things with it the more awfully complex and 
useless it is. inout must go. -- Andrei




Re: So what does (inout int = 0) do?

2016-04-15 Thread Adam D. Ruppe via Digitalmars-d

On Friday, 15 April 2016 at 09:07:27 UTC, Timon Gehr wrote:
Related: Phobos should never use is(typeof(...)). Contrary to 
popular belief, is(typeof(...)) is not the same as 
__traits(compiles,...).



I don't think it should be using __traits(compiles) either. I'd 
prefer to see built from the other reflection primitives... 
though I'll grant that compiles is flexible.


hasMember!(Range, "empty")

isn't as specific as the current test... and

is(typeof(Range.init.empty) : bool)

isn't as flexible (I don't think that takes an empty that returns 
an opCast:bool item)



But regardless, I still kinda prefer the idea of building these 
reflection helper functions so they do cover the cases nicely...


then a helper function that takes a list of conditions and tells 
you which one failed... hmm, this is getting interesting.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Andrei Alexandrescu via Digitalmars-d

On 4/15/16 8:59 AM, Nick Treleaven wrote:

On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:

Certainly, there have been a few times that it's come up in D.Learn
when folks ask what the heck it is, so there should be a few posts
floating around with an explanation. This is the only useful post that
I could find in a quick search though:

http://forum.dlang.org/post/mh68p8$2p56$1...@digitalmars.com


He says:

Alternatively, you could have the lambda take an R as a parameter. Or
fix the semantics ...


Assuming it works OK, that seems much cleaner:

(R r)
{
 if (r.empty) {}
 ...
}


That makes other unittests fail (those with noncopyable ranges).

Overall we really need to spend some time on making Phobos simpler and 
better. The mishmash of styles and variable quality of contributions has 
slowly been gnawing at the sheer quality of the code.



Andrei



Re: So what does (inout int = 0) do?

2016-04-15 Thread Nick Treleaven via Digitalmars-d

On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:
Certainly, there have been a few times that it's come up in 
D.Learn when folks ask what the heck it is, so there should be 
a few posts floating around with an explanation. This is the 
only useful post that I could find in a quick search though:


http://forum.dlang.org/post/mh68p8$2p56$1...@digitalmars.com


He says:
Alternatively, you could have the lambda take an R as a 
parameter. Or fix the semantics ...


Assuming it works OK, that seems much cleaner:

(R r)
{
if (r.empty) {}
...
}




Re: So what does (inout int = 0) do?

2016-04-15 Thread QAston via Digitalmars-d
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu 
wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152

There is no explanation to it in the source code, and the line 
blames to 
https://github.com/D-Programming-Language/phobos/pull/2661 
(irrelevant).




I've been wondering what that is myself, so I've just 
cargo-cult-copied it into my code. Thanks for the post.


Re: So what does (inout int = 0) do?

2016-04-15 Thread ixid via Digitalmars-d
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu 
wrote:
We want Phobos to be beautiful, a prime example of good D code. 
Admittedly, it also needs to be very general and efficient, 
which sometimes gets in the way. But we cannot afford an 
accumulation of mad tricks to obscure the large design.



Andrei


Why didn't we go with all functions being able to infer const, 
pure etc rather than just templates?




Re: So what does (inout int = 0) do?

2016-04-15 Thread Kenji Hara via Digitalmars-d
2016-04-15 14:38 GMT+09:00 Andrei Alexandrescu via Digitalmars-d <
digitalmars-d@puremagic.com>:

> On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:
>
>> On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d
>> wrote:
>>
>>> Consider:
>>>
>>>
>>> https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi
>>> tives.d#L152
>>>
>>> There is no explanation to it in the source code, and the line blames to
>>> https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).
>>>
>>> Commenting it out yields a number of unittest compilation errors,
>>> neither informative about the root of the problem and indicative as to
>>> how the parameter solves it.
>>>
>>> There are two issues here:
>>>
>>> 1. Once a problem/solution pair of this degree of subtlety crops up, we
>>> need to convince ourselves that that's sensible. If we deem it not so,
>>> we look into improving the language to make the problem disappear.
>>>
>>> 2. There needs to be documentation for people working on the standard
>>> library so they don't need to waste time on their own discovery process.
>>>
>>> We want Phobos to be beautiful, a prime example of good D code.
>>> Admittedly, it also needs to be very general and efficient, which
>>> sometimes gets in the way. But we cannot afford an accumulation of mad
>>> tricks to obscure the large design.
>>>
>>
>> IIRC, the problem has to do with ranges of inout elements working
>> correctly,
>> which gets really funky, because inout is a temporary thing and not a
>> full-on type constructor/qualifier. I believe that Kenji is the one that
>> implemented the fix, and I think that he explained it in the newsgroup at
>> some point. Certainly, there have been a few times that it's come up in
>> D.Learn when folks ask what the heck it is, so there should be a few posts
>> floating around with an explanation. This is the only useful post that I
>> could find in a quick search though:
>>
>> http://forum.dlang.org/post/mh68p8$2p56$1...@digitalmars.com
>>
>> inout attempts to solve a very real problem, but it does seem to be
>> surprisingly hard to understand and use prooperly even though it's
>> theoretically simple. And this bit with ranges is a quirk that I think
>> very
>> few people understand and remember. I usually forget exactly what it does
>> when it comes up and have to try and dig through the newsgroup archives
>> for
>> a previous discussion on it.
>>
>> - Jonathan M Davis
>>
>
> I think we should deprecate inout. For real. It costs way too much for
> what it does. For all I can tell most of D's proponents don't know how it
> works. -- Andrei
>


You should recall the history of inout.
http://wiki.dlang.org/DIP2

At first, It has designed to temporarily squash mutable/const/immutable
qualifiers on function argument inside function body. Therefore when inout
qualifier appears in function return type, but doesn't on parameter types,
we defined it an error.

However, I concluded that we can remove the restriction. When an inout
object arises from thin air, no one holds the qualifier of its real
instance. It means, the returned inout object can be converted to arbitrary
qualifiers without type system breaking.

Two years ago I opened an enhancement issue:
https://issues.dlang.org/show_bug.cgi?id=13006

And posted a pull request.
https://github.com/D-Programming-Language/dmd/pull/3740

Kenji Hara


Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 11:07, Timon Gehr wrote:

... Most of Phobos code assumes that ranges be struct fields.


Most of Phobos assumes that ranges can be



The fundamental problem is that inout is disallows certain kinds of
composition. ...


inout disallows



Re: So what does (inout int = 0) do?

2016-04-15 Thread Timon Gehr via Digitalmars-d

On 15.04.2016 05:10, Andrei Alexandrescu wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152
...



Related: Phobos should never use is(typeof(...)). Contrary to popular 
belief, is(typeof(...)) is not the same as __traits(compiles,...).


void main(){
int x;
static void foo(){
static assert(is(typeof({return x;})));
static assert(!__traits(compiles,{return x;}));
}
}


typeof suspends context access checks. This is almost never what you 
want when checking for compilability.




There is no explanation to it in the source code, and the line blames to
https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).

Commenting it out yields a number of unittest compilation errors,
neither informative about the root of the problem and indicative as to
how the parameter solves it.

There are two issues here:

1. Once a problem/solution pair of this degree of subtlety crops up, we
need to convince ourselves that that's sensible. If we deem it not so,
we look into improving the language to make the problem disappear.
...


Declaring variables with inout in their type is only allowed for stack 
variables in functions that have inout parameters. The (inout int) trick 
attempts to allow such types to be ranges.


It is not even a correct fix: Most of Phobos code assumes that ranges 
be struct fields. The following code causes a compilation failure in the 
guts of std.algorithm:


inout(int)[] foo(inout(int)[] x){
static assert(isInputRange!(typeof(x)));
return x.map!(x=>x).array;
}


What good is an "InputRange" that does not support map?


The fundamental problem is that inout is disallows certain kinds of 
composition. It's a flawed language primitive. The way to fix this is to 
have parametric polymorphism in the language.


Re: So what does (inout int = 0) do?

2016-04-15 Thread Guillaume Piolat via Digitalmars-d
On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu 
wrote:


I think we should deprecate inout. For real. It costs way too 
much for what it does. For all I can tell most of D's 
proponents don't know how it works. -- Andrei


This is the explanation I came up with, not sure if accurate. And 
only to teach myself the basics.

https://p0nce.github.io/d-idioms/#Knowing-inout-inside-out

I'm all for removing things!



Re: So what does (inout int = 0) do?

2016-04-15 Thread deadalnix via Digitalmars-d

On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:
IIRC, the problem has to do with ranges of inout elements 
working correctly, which gets really funky, because inout is a 
temporary thing and not a full-on type constructor/qualifier. I 
believe that Kenji is the one that implemented the fix, and I 
think that he explained it in the newsgroup at some point. 
Certainly, there have been a few times that it's come up in 
D.Learn when folks ask what the heck it is, so there should be 
a few posts floating around with an explanation. This is the 
only useful post that I could find in a quick search though:




Whatever the problem is, none of this seems like a good solution.



Re: So what does (inout int = 0) do?

2016-04-15 Thread w0rp via Digitalmars-d

On Friday, 15 April 2016 at 07:33:42 UTC, w0rp wrote:
I think it has something to do with making the function, in 
this case a lambda, inout, so that it can accept inout types. 
Then the typeof bit is a weird way to writing something like 
__traits(compiles, ...) , because functions which have no type 
result in void, and that fails the typeof check.


If we do end up replacing inout with something else, I would 
like something which solves the problem of declaring functions 
returning ranges of either mutable, const, or immutable. I've 
struggled with that before: 
https://github.com/w0rp/dstruct/blob/master/source/dstruct/graph.d#L628


To clarify my example. My problem was that I had a container 
which was immutable, and I wanted a range over the immutable 
elements, where the range itself is of course mutable. Getting 
that to work was a tad tricky. You can't take an inout() 
container and return an inout() range, because then an immutable 
container will produce an immutable range, which isn't useful. I 
don't think you can return a mutable range containing inout() 
elements either.


Re: So what does (inout int = 0) do?

2016-04-15 Thread w0rp via Digitalmars-d
I think it has something to do with making the function, in this 
case a lambda, inout, so that it can accept inout types. Then the 
typeof bit is a weird way to writing something like 
__traits(compiles, ...) , because functions which have no type 
result in void, and that fails the typeof check.


If we do end up replacing inout with something else, I would like 
something which solves the problem of declaring functions 
returning ranges of either mutable, const, or immutable. I've 
struggled with that before: 
https://github.com/w0rp/dstruct/blob/master/source/dstruct/graph.d#L628


Re: So what does (inout int = 0) do?

2016-04-14 Thread Walter Bright via Digitalmars-d

On 4/14/2016 8:10 PM, Andrei Alexandrescu wrote:

Commenting it out yields a number of unittest compilation errors, neither
informative about the root of the problem and indicative as to how the parameter
solves it.


https://issues.dlang.org/show_bug.cgi?id=15926


Re: So what does (inout int = 0) do?

2016-04-14 Thread Shammah Chancellor via Digitalmars-d
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu 
wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152

There is no explanation to it in the source code, and the line 
blames to 
https://github.com/D-Programming-Language/phobos/pull/2661 
(irrelevant).


Commenting it out yields a number of unittest compilation 
errors, neither informative about the root of the problem and 
indicative as to how the parameter solves it.


There are two issues here:

1. Once a problem/solution pair of this degree of subtlety 
crops up, we need to convince ourselves that that's sensible. 
If we deem it not so, we look into improving the language to 
make the problem disappear.


2. There needs to be documentation for people working on the 
standard library so they don't need to waste time on their own 
discovery process.


We want Phobos to be beautiful, a prime example of good D code. 
Admittedly, it also needs to be very general and efficient, 
which sometimes gets in the way. But we cannot afford an 
accumulation of mad tricks to obscure the large design.



Andrei


`(int inout = 0)` is not the only problem with that template -- 
and it's bothered me for years.


`is(typeof( () { ... } ) )` as a whole looks like a "trick" to 
me.  It's not going to be immediately obvious to someone who 
reads the D spec, and then that code, what that template does.


I think that behavioral type checks are common enough in D that 
it should have it's own first-class syntax.


-Shammah


Re: So what does (inout int = 0) do?

2016-04-14 Thread Vladimir Panteleev via Digitalmars-d
On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu 
wrote:
I think we should deprecate inout. For real. It costs way too 
much for what it does. For all I can tell most of D's 
proponents don't know how it works. -- Andrei


What would replace it in the case of classes, where you can't 
have templated virtual methods? Perhaps a mechanism to declare a 
templated virtual function, and a list of instantiations which 
will go into the vtable?


If we are to kill inout and replace it with something else, then 
it should support cases where inout failed, such as inout on the 
parameter of a delegate passed to the function (see: inout 
opApply).


Re: So what does (inout int = 0) do?

2016-04-14 Thread Andrei Alexandrescu via Digitalmars-d

On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:

On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d
wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi
tives.d#L152

There is no explanation to it in the source code, and the line blames to
https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).

Commenting it out yields a number of unittest compilation errors,
neither informative about the root of the problem and indicative as to
how the parameter solves it.

There are two issues here:

1. Once a problem/solution pair of this degree of subtlety crops up, we
need to convince ourselves that that's sensible. If we deem it not so,
we look into improving the language to make the problem disappear.

2. There needs to be documentation for people working on the standard
library so they don't need to waste time on their own discovery process.

We want Phobos to be beautiful, a prime example of good D code.
Admittedly, it also needs to be very general and efficient, which
sometimes gets in the way. But we cannot afford an accumulation of mad
tricks to obscure the large design.


IIRC, the problem has to do with ranges of inout elements working correctly,
which gets really funky, because inout is a temporary thing and not a
full-on type constructor/qualifier. I believe that Kenji is the one that
implemented the fix, and I think that he explained it in the newsgroup at
some point. Certainly, there have been a few times that it's come up in
D.Learn when folks ask what the heck it is, so there should be a few posts
floating around with an explanation. This is the only useful post that I
could find in a quick search though:

http://forum.dlang.org/post/mh68p8$2p56$1...@digitalmars.com

inout attempts to solve a very real problem, but it does seem to be
surprisingly hard to understand and use prooperly even though it's
theoretically simple. And this bit with ranges is a quirk that I think very
few people understand and remember. I usually forget exactly what it does
when it comes up and have to try and dig through the newsgroup archives for
a previous discussion on it.

- Jonathan M Davis


I think we should deprecate inout. For real. It costs way too much for 
what it does. For all I can tell most of D's proponents don't know how 
it works. -- Andrei





Re: So what does (inout int = 0) do?

2016-04-14 Thread Jonathan M Davis via Digitalmars-d
On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d 
wrote:
> Consider:
>
> https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi
> tives.d#L152
>
> There is no explanation to it in the source code, and the line blames to
> https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).
>
> Commenting it out yields a number of unittest compilation errors,
> neither informative about the root of the problem and indicative as to
> how the parameter solves it.
>
> There are two issues here:
>
> 1. Once a problem/solution pair of this degree of subtlety crops up, we
> need to convince ourselves that that's sensible. If we deem it not so,
> we look into improving the language to make the problem disappear.
>
> 2. There needs to be documentation for people working on the standard
> library so they don't need to waste time on their own discovery process.
>
> We want Phobos to be beautiful, a prime example of good D code.
> Admittedly, it also needs to be very general and efficient, which
> sometimes gets in the way. But we cannot afford an accumulation of mad
> tricks to obscure the large design.

IIRC, the problem has to do with ranges of inout elements working correctly,
which gets really funky, because inout is a temporary thing and not a
full-on type constructor/qualifier. I believe that Kenji is the one that
implemented the fix, and I think that he explained it in the newsgroup at
some point. Certainly, there have been a few times that it's come up in
D.Learn when folks ask what the heck it is, so there should be a few posts
floating around with an explanation. This is the only useful post that I
could find in a quick search though:

http://forum.dlang.org/post/mh68p8$2p56$1...@digitalmars.com

inout attempts to solve a very real problem, but it does seem to be
surprisingly hard to understand and use prooperly even though it's
theoretically simple. And this bit with ranges is a quirk that I think very
few people understand and remember. I usually forget exactly what it does
when it comes up and have to try and dig through the newsgroup archives for
a previous discussion on it.

- Jonathan M Davis



Re: So what does (inout int = 0) do?

2016-04-14 Thread Vladimir Panteleev via Digitalmars-d
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu 
wrote:

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152

There is no explanation to it in the source code, and the line 
blames to 
https://github.com/D-Programming-Language/phobos/pull/2661 
(irrelevant).


I heard that sometimes git blame can track moving data between 
files, but this is not such a case.


You can continue the blame by blaming the old path starting from 
the commit preceding that one:


git blame c828a08b64de067eeb2ddcad8fed22b2cd92e438^ -- range.d

Commenting it out yields a number of unittest compilation 
errors, neither informative about the root of the problem and 
indicative as to how the parameter solves it.


I'm not sure what errors you saw but the first one is that this 
fails:


static assert( isInputRange!(inout(int)[]));

git blame on this line points to:

https://issues.dlang.org/show_bug.cgi?id=7824


So what does (inout int = 0) do?

2016-04-14 Thread Andrei Alexandrescu via Digitalmars-d

Consider:

https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152

There is no explanation to it in the source code, and the line blames to 
https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).


Commenting it out yields a number of unittest compilation errors, 
neither informative about the root of the problem and indicative as to 
how the parameter solves it.


There are two issues here:

1. Once a problem/solution pair of this degree of subtlety crops up, we 
need to convince ourselves that that's sensible. If we deem it not so, 
we look into improving the language to make the problem disappear.


2. There needs to be documentation for people working on the standard 
library so they don't need to waste time on their own discovery process.


We want Phobos to be beautiful, a prime example of good D code. 
Admittedly, it also needs to be very general and efficient, which 
sometimes gets in the way. But we cannot afford an accumulation of mad 
tricks to obscure the large design.



Andrei