Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Stanislav Blinov

On Thursday, 30 January 2014 at 09:14:43 UTC, Cooler wrote:


Please stop explain me how fun3() works. I know that.
One of the main idea of D is that things must work as planned, 
or would not compile at all. First and second variants follow 
this idea. But fun3() can work not as planned on the caller 
side (depends on fun3() body's implementation).
The question again - may be prohibit fun3() variant? If we 
prohibit it, what use cases we could not implement with fun1() 
and fun2()?


Goodness... You've been shown this use case like a zillion times 
already: the caller manages her buffer, fun3() is allowed to 
change contents, but not reallocate caller's buffer.


fun1() can't provide that (const), fun2() cannot either, because 
it explicitly allows reallocation (ref). This behavior is only 
provided by fun3().


So it's either that, or indeed cases of I don't care about this 
array, which Maxim Fomin has mentioned.


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Maxim Fomin

On Thursday, 30 January 2014 at 09:14:43 UTC, Cooler wrote:
If you want to modify the slice and make changes visible in 
caller, you should use ref. If you don't care whether changes 
are visible in caller, you can omit any attributes and use 
plain array. This belongs to the case you are asking about. If 
you don't want to change array in callee, pass it as const 
qualified.


Now, after rethinking the issue I am inclining that don't 
care whether changes are visible for caller is not very 
wrong, but not very good design. Ideally it should be 
specified to avoid unexpected problems to pop up. So yes, it 
is better to qualify array.


Another point. This casino games of whether changes would be 
visible or not is direct consequence of how slices are 
implemented (and how runtime service them). Remember, that 
many features in D work in a strange way not because of wise 
design but as a consequence of not fully thought design (like 
array). As a result, some features work in not best way they 
should. Although many folks in newsgroups would eagerly say 
that you don't understand the lang, it wouldn't make a bad 
design a good one.


Please stop explain me how fun3() works. I know that.


This is first problem. You are being explained what is the 
*purpose* of the fun3() but you repeatedly fail to accept it.


One of the main idea of D is that things must work as planned, 
or would not compile at all.


Outcryingly wrong. Study bugzilla which shows how some things go 
wrong and read DIPs to learn that there are some issues in the 
language for which the communitty still struggles to formulate 
good solution.


First and second variants follow this idea. But fun3() can work 
not as planned on the caller side (depends on fun3() body's 
implementation).


Many things can work not as intended. Please read forums, 
bugzilla, etc. I bet passing array will not be the only thing you 
find confusing.



The question again - may be prohibit fun3() variant?


Prohibiting code like:
void foo(int[] arr) {}

would break hell of a code and pose doubts on what happens with 
arrays if so simple construction is prohibited. In addition, I 
mentioned that don't care is probably sometimes an option. 
Emitting warning here has some merits but it would be consitently 
ignored (I expect).


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread bearophile

Cooler:

Again - stop consider current state of D implementation. 
Consider how we can make D better. I think fun3() push 
programmers to make errors.


I think functions like void fun(int[] a){} are bug prone, because 
you seem to change the length of the array inside the function, 
or if you perform an append you modify a new memory zone, but 
such changes are invisible from the caller. Some times this is 
what you want, and in some cases this is a programmer mistake 
(this bug happened to me several times).


But I don't know what to change and if this situation can be 
improved now. Perhaps all that's left to improve is to add tests 
to a D lint that warns against this possible source of bugs.


Bye,
bearophile


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Maxim Fomin

On Thursday, 30 January 2014 at 10:49:42 UTC, Cooler wrote:
Now I am trying to speak ideally. What ideal language should 
be, not the practical implementation.



...

Again - don't look back. Consider how we can make D better.


...
Again - stop consider current state of D implementation. 
Consider how we can make D better. I think fun3() push 
programmers to make errors.


Looks like you are overestimating yourself.

Now, try:
1) write pull request to reject the code
2) convince developers somehow that your proposal is good
3) convince Walter to accept the change
4) after merging pull convince angry maintainers that it is good 
idea to reject unqualified array passing because Cooler tries to 
make the language better


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Dicebot

On Wednesday, 29 January 2014 at 14:34:54 UTC, Cooler wrote:

Here is ambiguity.
void fun3(int[] x){ x ~= 5; ... }
auto a = new int[10];
fun3(a); // Here content of a may be changed or may be not 
changed. Depends on the buffer size that system will allocate 
for a array.


You use very subjective meaning for ambiguity, one that is 
never normally used in programming language context. Normally 
term ambiguity is applied only when _compiler_ can't reliably 
decide meaning of the code snippet and needs to resort to special 
casing.


You are correct in notion that you can't make any reasonable 
judgement yourself about content of a after `fun3` call but same 
applies to `fun2` - it can be or not be modified. It is expected 
- to express all semantics of function body in function signature 
one would have needed to make it of comparable length and 
complexity.


In practice you need always to assume the worst - everything is 
modified and nothing can be trusted unless explicitly qualified 
other way around.


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

kOn Wed, 29 Jan 2014 05:55:56 -0500, Cooler kul...@hotbox.ru wrote:


Consider 3 functions taking array as an argument:

void fun1(in  int[] x){...}
void fun2(ref int[] x){...}
void fun3(int[] x){...}

auto a = new int[10];

fun1(a); // Guaranteed that a will not be changed
fun2(a); // Guaranteed that we will see any change to a, made in fun2()
fun3(a); // Changes to a in fun3() may be or may be not visible to the  
caller


In case of fun3() we have ambiguous behaviour, depending on the body of  
the function.


Am I right?


Yes.


Is that intentional?


Yes.

I read the rest of the discussion. Arrays are hard to understand in D,  
especially if you have preconceived notions from other languages. But I  
would point out that fun2 does not guarantee anything more than fun3:


void fun2(ref int [] x)
{
   fun3(x);
}

It is an intrinsic property of slices that they do not own the data  
pointed at. You cannot guarantee that one slice's changes will affect  
another slice, AS LONG AS one slice is increasing its length. If you avoid  
increasing the length, then the results are deterministic. As I said in  
the article, avoid increasing the length, and THEN changing the original  
data. If you do that, you should have quite predictable results. If your  
code must do otherwise, explain in the documentation what should happen  
(i.e. don't use the passed-in slice after the function), and use some of  
the tricks to avoid it (use ref, or return the new slice data).


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 09:18:40 -0500, Cooler kul...@hotbox.ru wrote:


Forgot to mention :)

I read the rest of the discussion. Arrays are hard to understand in D,  
especially if you have preconceived notions from other languages. But  
I would point out that fun2 does not guarantee anything more than  
fun3:


void fun2(ref int [] x)
{
  fun3(x);
}
But I would point out that fun2 does not guarantee anything more than  
fun3: - fun2() cannot guarantee anything because it calls fun3() which  
in turn cannot guarantee anything.


Right, but you said this:


fun2(a); // Guaranteed that we will see any change to a, made in fun2()


Which is false. That was my point.

-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 09:07:14 -0500, Cooler kul...@hotbox.ru wrote:

If I don't want that fun() will change my array, i have to use fun1()  
variant.
If I want fun() will change my array, i have to use fun2() variant. What  
fun2() do with it's argument inside it's body - not my business.


No. You can use fun3 variant as well:

void fun3(int[] x)
{
   x[] = 0; // guaranteed to be seen by caller.
}



1. For example somebody already implemented fun1() and fun2() variants,  
as in my first post. This variants understandable and predictable. What  
can push me to ask another person for fun3() implementation, while it  
result is unpredictable, until you know fun3() body?


The only reason to have both fun2 and fun3 variants is if you want to  
handle both l-value and r-value options differently. There would be very  
few use cases which make sense AND return void.


You usually want one or the other.



2. You wrote If your code must do otherwise, explain in the  
documentation what
should happen. That exactly what I am trying to discuss here. Instead  
of writing some documentation, just warn (and may be prohibit in far-far  
future) about such possible unpredictability during compilation.


No, because you are not understanding the effect of the attributes, and  
who is responsible for what.


1. Banning such signatures does NOT accomplish what you want.
2. Such signatures do NOT guarantee what happens inside the function.

Having the compiler ban the problem where you expect the caller to see  
your changes, but they don't, is akin to just making the compiler able to  
detect all logic bugs. It's not possible (NP complete). The compiler just  
doesn't know what you really want to do.


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 10:24:14 -0500, Cooler kul...@hotbox.ru wrote:


On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:

On Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:
If I use fun2() I expect that fun2() will change the content of my  
array, and all changes I will see. If I don't want any change to my  
array, I will use fun1(). What should I want to use fun3()?


For changes to content of array but not array itself.


I agree. I just want that the case can be expressed in language syntax  
more obvious - something like fun(int[] const x){} to emphasize that I  
understand that fun() can change content of array, and cannot change the  
{pointer,size} pair.


That's what fun(int[] x) does :)

-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Tobias Pankrath

On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:
I agree. I just want that the case can be expressed in 
language syntax more obvious - something like fun(int[] 
const x){} to emphasize that I understand that fun() can 
change content of array, and cannot change the {pointer,size} 
pair.


That's what fun(int[] x) does :)

-Steve


Again...
void fun(int[] x){ x ~= 5; }
auto a = new int[10];
fun(a); // Can you predict the content of 'a'?



It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 10:49:34 -0500, Cooler kul...@hotbox.ru wrote:


On Thursday, 30 January 2014 at 15:29:50 UTC, Steven Schveighoffer wrote:

On Thu, 30 Jan 2014 10:24:14 -0500, Cooler kul...@hotbox.ru wrote:


On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:


I agree. I just want that the case can be expressed in language syntax  
more obvious - something like fun(int[] const x){} to emphasize that  
I understand that fun() can change content of array, and cannot change  
the {pointer,size} pair.


That's what fun(int[] x) does :)

-Steve


Again...
void fun(int[] x){ x ~= 5; }
auto a = new int[10];
fun(a); // Can you predict the content of 'a'?


I suspect you mean:

void fun(int[] x) {x.length += 1; x[0] = 5;}

I cannot predict what the caller will see. But this is not a problem of  
*signatures*. The caller will not see ANY changes to {pointer,size} pair  
of x. That is the point -- it's passed by value.


Note that this implementation is completely predictable:

void fun(int[] x) {x[0] = 5; x.length += 1;}

I want to stress that just because you can find an implementation that has  
a bug doesn't mean that there is an opportunity for the compiler to detect  
that bug, especially a logic bug. The compiler simply cannot know what you  
are thinking.



In your case:
void fun(int[] x){ x = [1, 2]; } // Compilation ok. Implementation's  
error.
The fun() implementer made error and think that caller will get new  
array. But it will get it only at runtime!

If we for example (just for example) have
void fun(int[] const x){ x = [1, 2]; } // Compilation error.


I see very little value in that. We don't need to obliterate a tremendous  
amount of slice usage (not mentioning how much code will have to be  
updated) in order to help newbies understand how slices work.


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 11:48:50 -0500, Cooler kul...@hotbox.ru wrote:



Please understand - I am not against void foo(int[] x){}


From an earlier post by you:

May be just prohibit at language level the case of fun3() function, to  
do not allow unpredictable behavior?


I thought that this meant you were against it?

I am for predictability of behavior. You suggest to describe function's  
behavior in documentation - quotation from your article It is a good  
idea to note in the documentation how the passed in slice might or might  
not be
overwritten. My idea is that all potential errors must be detected as  
soon as possible.


You cannot eradicate all errors. The intentions of a function are not  
apparent to the compiler. Maybe the intention is to use the argument as a  
buffer, and the caller should not care what happens to the buffer inside  
the function.


Adding yet another attribute is going to increase language complexity for  
almost no benefit. It does not guarantee unambiguity because you have no  
idea what the author of the function is going to do.


The D principle - The program compile and runs as expected, or not  
compile at all.


This is a fantasy. The compiler cannot know what you expect.

If you really need to call function that can change content of an array,  
but cannot change size of an array the language syntax should allow  
express it in function signature. I consider void fun(int[] const x){}  
more error prone than void fun(int[] x){} and for the caller and for  
implemeter.


Not sure if something is mixed up there. I think void fun(int[] x) is  
sufficient to describe what you say. The function cannot alter x's array  
bounds at all, and can alter it's data.




I see very little value in that. We don't need to obliterate a  
tremendous  amount of slice usage (not mentioning how much code will  
have to be  updated) in order to help newbies understand how slices  
work.

Any idea can be rejected by this sentence.


No, only ideas that force people to change millions of lines of code, and  
provide scant benefits instead of taking 5 minutes to explain no, just  
use x[0..2] = [1, 2] or just use ref int[] x depending on the goal.


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 12:07:07 -0500, Cooler kul...@hotbox.ru wrote:


On Thursday, 30 January 2014 at 16:18:33 UTC, Steven Schveighoffer wrote:



void foo(int x)
{
   x = 5;
}

hey, why doesn't that work! Setting a parameter to another value  
should be illegal!


Difference is here.
void foo(int x){} - the caller will NEVER see any change to 'x'.
void foo(int[] x){} - the caller MAY or MAY NOT see changes to 'x'.


This is incorrect:

foo(int[] x){} - The caller will see changes to data 'x' references.

A slice is a reference type, it references a specific block of data. It's  
more akin to a pointer than an int.


I could change my example:

void foo(int *x)
{
   int n = 3;
   x = n;
}

hey, why doesn't x now point to 3? Should be illegal!

-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Maxim Fomin

On Thursday, 30 January 2014 at 16:48:51 UTC, Cooler wrote:
On Thursday, 30 January 2014 at 16:18:33 UTC, Steven 
Schveighoffer wrote:

void foo(int x)
{
  x = 5;
}

hey, why doesn't that work! Setting a parameter to another 
value should be illegal!


-Steve


Please understand - I am not against void foo(int[] x){}
I am for predictability of behavior.


Predictability of behavior is not a principle of D and even if it 
would be, it can't be applied blindly. D is not a formal 
mathematic system.


You suggest to describe function's behavior in documentation - 
quotation from your article It is a good idea to note in the 
documentation how the passed in slice might or might not be
overwritten. My idea is that all potential errors must be 
detected as soon as possible.


It is impossible to detect all errors in D per se, let alone 
taking into account separate compilation model. In some 
circumstances compiler can guess possible ways, but particular 
case we discussing is so common, that nothing can be done to 
'fix' it. By the way, this case is not strictly speaking an 
error. It is error in context when caller cares about changes but 
this can be hardly verified at compile time (compiler need to 
read brain to know it).


The D principle - The program compile and runs as expected, or 
not compile at all.


It is all talk. Trying to apply this 'principle' in all cases is 
too naive.


If you really need to call function that can change content of 
an array, but cannot change size of an array the language 
syntax should allow express it in function signature. I 
consider void fun(int[] const x){} more error prone than 
void fun(int[] x){} and for the caller and for implemeter.




Personally this syntax is awful.

By the way, there is another similar issue in D:

import std.stdio;

void foo(int[int] aa)
{
aa[1] = 1;
}

void main()
{
int[int] aa;
foo(aa);
writeln(aa); // []
aa[0] = 0;
foo(aa);
writeln(aa); // [0:0, 1:1]
aa = null;
foo(aa);
writeln(aa); // []
}

Here changes in AA array will be visible conditional that array 
is non null. If it is null, changes will be lost. This is another 
example of situation of the caller MAY or MAY NOT see changes 
to (citing your post above). In general, such 
semivalue-semireference semantic is produced when there is 
pointer wrapped into struct (doesn't matter whether it is opaque 
lang type or user defined). This happens in some language types, 
but may be also in user defined types. I don't think that 
verifying arbitrary semantic is compiler job.


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 12:38:57 -0500, Cooler kul...@hotbox.ru wrote:


The D principle - The program compile and runs as expected, or not  
compile at all.


This is a fantasy. The compiler cannot know what you expect.

The language is needed to express your intentions to the compiler.


Anything that the compiler cannot enforce is just documentation. Does it  
matter whether the documentation is in a comment or part of the signature?


The language should be expressive as possible. My point is to push  
programmers to write correct software. I just ask these forum to think  
about topic. If everybody satisfied by void fun(int[] x){} behavior,  
then I just go...


I'm not trying to be a bully or anything, but you are not understanding  
that what you want is a guarantee of logic, that the compiler cannot  
possibly enforce. Your example (setting a variable to another value) being  
rejected is easy to work around, just use another variable that doesn't  
have that restriction. There are so many examples of behavior-enforcing  
features that result in something that the creator of the feature didn't  
want or expect. Keep in mind there are years of projects that have been  
written assuming that you can use a standard slice in the signature of a  
function, we don't want to invalidate all that code just because  
programmers sometimes write buggy code.


But I encounter a bug in my program that was due to my misusing of such  
signature.


Here's where the gray area is. If you make this error once or twice, but  
never again, is it worth changing the language over? Probably not. But if  
you make this error every day, even KNOWING what will happen, it's worth  
looking into. But any changes have to avoid a negative impact on existing  
code as much as possible. Think of the person who knows how slices work,  
who very seldom makes this mistake, and who now has to go through all his  
code and make this change, never finding an instance where it makes a  
difference.


At this point, I'm not sure what you are proposing, but I don't think  
there is much value in changing the way slice passing works.


If you really need to call function that can change content of an  
array, but cannot change size of an array the language syntax should  
allow express it in function signature. I consider void fun(int[]  
const x){} more error prone than void fun(int[] x){} and for the  
caller and for implemeter.


Not sure if something is mixed up there. I think void fun(int[] x) is  
sufficient to describe what you say. The function cannot alter x's  
array bounds at all, and can alter it's data.


Here is the reason why i post the topic on this forum. You think one  
way, I think another way. I wanted to discuss what think other people.  
But looks like still nobody can understand my point, or may be I cannot  
express it...


By mixed up, I meant that you seemed to be valuing the int[] x version  
over the int[] const x version.


Other than that, what I stated is an indisputable fact -- the function  
cannot alter x's bounds.


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Steven Schveighoffer

On Thu, 30 Jan 2014 13:58:55 -0500, Cooler kul...@hotbox.ru wrote:

The D principle - The program compile and runs as expected, or not  
compile at all.


This is a fantasy. The compiler cannot know what you expect.

The language is needed to express your intentions to the compiler.


Anything that the compiler cannot enforce is just documentation. Does  
it matter whether the documentation is in a comment or part of the  
signature?
Why we need const keyword, while we can just put I promise do not  
change it in the documentation?


const is only useful in cases where references are involved. In this case,  
you want to make the *copied* data constant, in hopes that you then can't  
accidentally stop referencing the original.


In another example, there is little to be gained from a signature such as:

void foo(const int x);

What does this say about foo? Nothing. I can pass in a mutable, const, or  
immutable int, because a copy is made. It doesn't provide any more  
guarantees to the caller than:


void foo(int x);

Likewise, your proposed int[] const would not guarantee anything extra  
to the caller beyond int[], because both are copies put onto the stack.  
The function has no access to the original values.


Arrays in D are hard to understand. They don't behave like arrays in most  
other languages. But they foster a different mindset I think, that results  
in some of the fastest code on the planet. But one has to understand the  
semantics of syntax if they want to properly use the language. For  
functions which append/extend and then write data to the prior piece (the  
only non-deterministic case), special care has to be taken to explain this  
to the caller. I would think a mechanism to attempt detecting this and  
flagging it would be a worthy lint tool feature. But not a language or  
compiler feature. There is just simply no way to say that is always bad  
or that you know what the intentions of the author are.


The other case you specified, when the author re-assigns a slice and  
expects it to be a memcpy or to re-bind the calling parameter, the result  
is deterministically the wrong result, and the coder will notice it right  
away (and hopefully correct their understanding). I don't think we need a  
language feature for that, just documentation (which I think we have).


Let me also suggest you use scope statements to verify at runtime that the  
case you intend to prevent doesn't actually happen:


void foo(int[] x)
{
   const origx = x;
   scope(exit) assert(origx.ptr == x.ptr);
   ...
}

While not perfect, and not static, it should at least avoid subtle bugs  
(and can be turned off in release mode).


-Steve


Re: Array as an argument, ambiguous behaviour.

2014-01-30 Thread Jesse Phillips

On Wednesday, 29 January 2014 at 10:55:57 UTC, Cooler wrote:

Consider 3 functions taking array as an argument:

void fun1(in  int[] x){...}
void fun2(ref int[] x){...}
void fun3(int[] x){...}

auto a = new int[10];

fun1(a); // Guaranteed that a will not be changed
fun2(a); // Guaranteed that we will see any change to a, made 
in fun2()
fun3(a); // Changes to a in fun3() may be or may be not 
visible to the caller


In case of fun3() we have ambiguous behaviour, depending on the 
body of the function.


Am I right?
Is that intentional?


I believe what you are asking for is head const. D does not do 
this, search for head const dlang and you'll probably find some 
discussion in it.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Tobias Pankrath

On Wednesday, 29 January 2014 at 10:55:57 UTC, Cooler wrote:

Consider 3 functions taking array as an argument:

void fun1(in  int[] x){...}
void fun2(ref int[] x){...}
void fun3(int[] x){...}

auto a = new int[10];

fun1(a); // Guaranteed that a will not be changed
fun2(a); // Guaranteed that we will see any change to a, made 
in fun2()
fun3(a); // Changes to a in fun3() may be or may be not 
visible to the caller


In case of fun3() we have ambiguous behaviour, depending on the 
body of the function.


Am I right?
Is that intentional?


Arrays are a pair of pointer and length.

fun1 marks the pointer, the length and the data pointed as const.
fun3 marks nothing const, but since pointer and length are passed 
by value, you'll only see changes to the content of x.
fun2 is like fun3, but pointer and length are itself passed by 
reference.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread simendsjo

On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:
Thank you for detailed explanation. But the question is - Is 
that correct that language allows ambiguous behavior?


Could you expand your example?

fun(int[] a) {} is passing a by value, that is, the pointer and 
length is copied over to fun. Any changes to the elements of a 
will be visible, but if you reassign a directly or indirectly 
(expanding it so it needs to be copied to a new memory location), 
the changes are not visible.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Tobias Pankrath

On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:
Thank you for detailed explanation. But the question is - Is 
that correct that language allows ambiguous behavior?


Where is it ambiguous?


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread simendsjo

On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:
On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath 
wrote:

On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:
Thank you for detailed explanation. But the question is - Is 
that correct that language allows ambiguous behavior?


Where is it ambiguous?


Ambiguity is here...
When I call fun1() or fun2() I know the behavior directly from 
function signature (read the comments in my first post). For 
fun3() case the caller side don't know the behavior directly 
from function signature. To know what will happen with array 
a, the caller must see to fun3() body.
Ambiguity is - in first and second cases the caller knows what 
happens with a, but in third case the caller does not know 
what happens with a.


'in' is a shorthard for 'const scope'.
'const' means that the callee cannot change the passed in 
parameter in any way, including anything available through that 
type (for example x[0])
'scope' means it cannot leave the scope of the callee - that it 
cannot be stored away anywhere.
'ref' means that the parameter is passed by reference, and thus 
might be reassigned or changed in any way.


No parameters means that it's mutable, but the reference cannot 
change.


I don't see any ambiguities here.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Sergei Nosov

On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:
On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath 
wrote:

On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:
Thank you for detailed explanation. But the question is - Is 
that correct that language allows ambiguous behavior?


Where is it ambiguous?


Ambiguity is here...
When I call fun1() or fun2() I know the behavior directly from 
function signature (read the comments in my first post). For 
fun3() case the caller side don't know the behavior directly 
from function signature. To know what will happen with array 
a, the caller must see to fun3() body.
Ambiguity is - in first and second cases the caller knows what 
happens with a, but in third case the caller does not know 
what happens with a.


I believe you encounter an array reallocation.

If fun3 doesn't change the size of the array - you will see every 
change made by fun3 to the contents of `a` (but the `a` itself 
cannot be changed - only the contents). No other way around.


If, however, in fun3 you change the size of the array - it may 
reallocate. Like, if you're appending to `x` - it will allocate a 
new array and make x point to it. Now `a` and `x` point to 
distinct arrays. And any change you do using `x` won't be seen by 
`a`. And, yes, this is the intended behavior.




Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Ali Çehreli

On 01/29/2014 02:55 AM, Cooler wrote:

Consider 3 functions taking array as an argument:

void fun1(in  int[] x){...}
void fun2(ref int[] x){...}
void fun3(int[] x){...}

auto a = new int[10];

fun1(a); // Guaranteed that a will not be changed
fun2(a); // Guaranteed that we will see any change to a, made in fun2()
fun3(a); // Changes to a in fun3() may be or may be not visible to the
caller

In case of fun3() we have ambiguous behaviour, depending on the body of
the function.

Am I right?
Is that intentional?


Yes, that is how slices work in D. The following article explains the 
non-determinism that you mention:


  http://dlang.org/d-array-article.html

Ali



Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Sergei Nosov

On Wednesday, 29 January 2014 at 15:11:33 UTC, Cooler wrote:
Yes, that is how slices work in D. The following article 
explains the non-determinism that you mention:


 http://dlang.org/d-array-article.html

Ali


Thank you for the article.
Quotation from the article It is a good idea to note in the 
documentation how the passed in slice might or might not be 
overwritten.
May be just prohibit at language level the case of fun3() 
function, to do not allow unpredictable behavior?


This behavior is just a consequence of the deliberate decision on 
how arrays should be implemented.


Any decision would be a trade-off. Like, if you just disallow 
this signature, you will have to use .dup at the caller side if 
you want the semantics of fun3. And often this copy might be 
unnecessary.


It's really like a ball under the carpet. You make it flat in one 
place, but the ball pops up in the other.


The trade-off that D chooses is pretty reasonable. You just have 
to accept that and get used to it.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Tobias Pankrath

On Wednesday, 29 January 2014 at 15:11:33 UTC, Cooler wrote:
Yes, that is how slices work in D. The following article 
explains the non-determinism that you mention:


 http://dlang.org/d-array-article.html

Ali


Thank you for the article.
Quotation from the article It is a good idea to note in the 
documentation how the passed in slice might or might not be 
overwritten.
May be just prohibit at language level the case of fun3() 
function, to do not allow unpredictable behavior?


It's not unpredictable, at least not more unpredictable then fun2.

Should we dissallow this two?

int[] a = [1,2,3,4];
b = a;
b ~= [5, 6, 7, 8];



Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Tobias Pankrath

On Wednesday, 29 January 2014 at 15:38:34 UTC, Cooler wrote:
It's not unpredictable, at least not more unpredictable then 
fun2.


Should we dissallow this two?

int[] a = [1,2,3,4];
b = a;
b ~= [5, 6, 7, 8];


You don't understand me. You consider that I am author of the 
fun() and the caller side.
Read two post above 
http://forum.dlang.org/post/dxqxlhyhmdfuashhm...@forum.dlang.org


I consider that author of fun() and author of caller side are 
different persons. They must agree between them how to provide 
some functionality.
If I fun()'s author why do I need to provide fun3() if I 
already provided fun1() and fun2()?
I I caller's author - why may I require fun3() variant, if I 
already have fun1() and fun2()?


Oh, I guess I understood quite well. I just don't see a special 
problem with arrays, it's just the same as any other aliasing 
issue. Take this for example:


void funS(S* s); // S is a struct, maybe containing a ptr and a 
length member :-)


Should we disallow this as well? When I give a unqualified 
pointer to a function, the only guarantee I get is that it's 
pointing to the same location after the call. It's the same with 
arrays.


And since we have this problem every time we pass a pointer to 
function I don't see why arrays should get special treatment.




Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Tobias Pankrath

On Wednesday, 29 January 2014 at 16:01:08 UTC, Cooler wrote:


Do you read my post? I am answering... why do I need fun3() if 
I already have fun1() and fun2().


fun3 guarantees that the argument has the same length for example.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Stanislav Blinov

On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:

Where argument has the same length? After function call, or 
inside function? I don't understand what my intention should be 
to push me to use fun3()?


Gosh. To allow the function to modify the contents, but not the 
size of the array.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Stanislav Blinov

On Wednesday, 29 January 2014 at 16:54:27 UTC, Cooler wrote:

On Wednesday, 29 January 2014 at 16:36:44 UTC, Stanislav Blinov
wrote:

On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:

Where argument has the same length? After function call, or 
inside function? I don't understand what my intention should 
be to push me to use fun3()?


Gosh. To allow the function to modify the contents, but not 
the size of the array.


Сам то понял чего написал??? :)


Yes I did.


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Maxim Fomin

On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:
On Wednesday, 29 January 2014 at 16:15:36 UTC, Tobias Pankrath 
wrote:

On Wednesday, 29 January 2014 at 16:01:08 UTC, Cooler wrote:


Do you read my post? I am answering... why do I need fun3() 
if I already have fun1() and fun2().


fun3 guarantees that the argument has the same length for 
example.


Where argument has the same length? After function call, or 
inside function? I don't understand what my intention should be 
to push me to use fun3()?


If you want to modify the slice and make changes visible in 
caller, you should use ref. If you don't care whether changes are 
visible in caller, you can omit any attributes and use plain 
array. This belongs to the case you are asking about. If you 
don't want to change array in callee, pass it as const qualified.


Now, after rethinking the issue I am inclining that don't care 
whether changes are visible for caller is not very wrong, but 
not very good design. Ideally it should be specified to avoid 
unexpected problems to pop up. So yes, it is better to qualify 
array.


Another point. This casino games of whether changes would be 
visible or not is direct consequence of how slices are 
implemented (and how runtime service them). Remember, that many 
features in D work in a strange way not because of wise design 
but as a consequence of not fully thought design (like array). As 
a result, some features work in not best way they should. 
Although many folks in newsgroups would eagerly say that you 
don't understand the lang, it wouldn't make a bad design a good 
one.