Re: Proposal: Object/?? Destruction

2017-10-29 Thread Q. Schroll via Digitalmars-d

On Monday, 16 October 2017 at 23:29:46 UTC, sarn wrote:

On Sunday, 15 October 2017 at 15:19:21 UTC, Q. Schroll wrote:

On Saturday, 14 October 2017 at 23:20:26 UTC, sarn wrote:
On Saturday, 14 October 2017 at 22:20:46 UTC, Q. Schroll 
wrote:
Therefore, and because of brackets, you can distinguish f(1, 
2) from f([1, 2]).


But in f([1, 2]), it's ambiguous (just by parsing) whether 
[1, 2] is a tuple literal or a dynamic array literal.


It would be a tuple if that's the best match, otherwise 
conversion to int[] is tried.

...

You'd need to use a prefix or something to the bracket syntax.
[snip]


I just argued, you don't!


But have you thought through all the implications?


Yes. No weirdness is being introduced that is not there already. 
Maybe I have overseen something; I will not give you or anyone 
else a guarantee for the solution to work perfectly. I've thought 
through the case very long.
An open question is allowing partly const/immutable/shared (cis) 
tuples. As for now, I didn't care. Even c/i/s-homogeneus tuples 
(the tuple is c/i/s as a whole or not) would be a win in my 
opinion. One rarely needs tuples with one component immutable but 
the other one mutable. This is what a named struct is for. On the 
other hand, I don't know of any issues having a to partly c/i/s 
std.typecons.Tuple.



Take this code:

void main(string[] args)
{
import std.stdio : writeln;
writeln([1, 3.14]);
}

As you're probably 100% aware, this is totally valid D code 
today.  [1, 3.14] becomes a double[] because 1 gets converted 
to a double.


Right conclusion with insufficient explanation. [1, 3.14] is a 
static array in the first place. It occupies a fully inferred 
template parameter position. I don't know the implementation, but 
every time I tested, it behaves as if typeof(expr) is being used 
after the bang to set the template argument manually (even for 
Voldemort types etc. where typeof is sometimes impossible due to 
missing frame pointers). typeof returns "dynamic array of T" for 
array literals. This is all the weirdness going on here. It is 
present today and would remain present if you interpret [1, 3.14] 
as a tuple.


If this kind of behaviour changes, code will break, so you'll 
need a bunch of exceptions to the "it would be a tuple if 
that's the best match" rule.


The only exception is typeof and (therefore, I don't know...) 
template inference.


Also, for the same backwards compatibility reasons, it would be 
impractical in most cases to add any tuple overloads to most 
existing standard library functions that currently accept 
slices or arrays, but presumably new functions would be meant 
to take advantage of the new syntax (else there wouldn't be 
much point creating a new syntax).


You don't have to as long as you don't want to support tuples 
explicitly; otherwise you have to. If you have a void f(int, 
double), you cannot plug in [1, 3.14]. You can use some expand to 
do it. You wouldn't want to either. If you have something 
*explicitly typed* as a tuple, e.g.

[int, double] tup = [1, 3.14];
you can make the call f(tup) because auto expansion does its job. 
This is the use case. If you have void f([int, double]), you can 
plug in tuple literals.
If you use a tuple literal for a function call, the compiler will 
search for explicit matches for tuples. If it cannot find any, 
conversion to a dynamic array happens.


So, a literal like [1, 3.14] would basically be a tuple, but 
would be converted to double[] in a bunch of special cases for 
historical reasons.


Yes. It would be converted in almost all cases -- the same with 
static arrays -- because the best match doesn't occur very often 
and typeof never returns static arrays or tuples for literals.


If you're not sure if this is really a problem, take a look at 
the confusion caused by the magic in {} syntax:


https://forum.dlang.org/thread/ecwfiderxbfqzjcyy...@forum.dlang.org
https://forum.dlang.org/thread/ihsmxiplprxwlqkgw...@forum.dlang.org
https://forum.dlang.org/thread/qsayoktyffczskrnm...@forum.dlang.org


This is completely unrelated. Concerning the issues people have 
with (..) => { .. }, I've filed an enhancement request to 
deprecate it in that specific case: 
https://issues.dlang.org/show_bug.cgi?id=17951


To be totally honest, I still don't see what's wrong with just 
creating a new bracket syntax, instead of adding more magic to 
[] (or () for that matter).


It's not adding any magic to [] that isn't there already. The 
other proposals are adding magic to (). Even some mathematicians 
use chevrons (angle brackets) for tuples as they see parentheses 
as indicators of precedence. I'd vote against angle brackets, see 
C++ templates for reasons. Logicians and haskellers even don't 
need parentheses for function calls.


Could I convince you?


Re: Proposal: Object/?? Destruction

2017-10-16 Thread sarn via Digitalmars-d

On Sunday, 15 October 2017 at 15:19:21 UTC, Q. Schroll wrote:

On Saturday, 14 October 2017 at 23:20:26 UTC, sarn wrote:

On Saturday, 14 October 2017 at 22:20:46 UTC, Q. Schroll wrote:
Therefore, and because of brackets, you can distinguish f(1, 
2) from f([1, 2]).


But in f([1, 2]), it's ambiguous (just by parsing) whether [1, 
2] is a tuple literal or a dynamic array literal.


It would be a tuple if that's the best match, otherwise 
conversion to int[] is tried.

...

You'd need to use a prefix or something to the bracket syntax.
[snip]


I just argued, you don't!


But have you thought through all the implications?

Take this code:

void main(string[] args)
{
import std.stdio : writeln;
writeln([1, 3.14]);
}

As you're probably 100% aware, this is totally valid D code 
today.  [1, 3.14] becomes a double[] because 1 gets converted to 
a double.  If this kind of behaviour changes, code will break, so 
you'll need a bunch of exceptions to the "it would be a tuple if 
that's the best match" rule.  Also, for the same backwards 
compatibility reasons, it would be impractical in most cases to 
add any tuple overloads to most existing standard library 
functions that currently accept slices or arrays, but presumably 
new functions would be meant to take advantage of the new syntax 
(else there wouldn't be much point creating a new syntax).


So, a literal like [1, 3.14] would basically be a tuple, but 
would be converted to double[] in a bunch of special cases for 
historical reasons.


If you're not sure if this is really a problem, take a look at 
the confusion caused by the magic in {} syntax:


https://forum.dlang.org/thread/ecwfiderxbfqzjcyy...@forum.dlang.org
https://forum.dlang.org/thread/ihsmxiplprxwlqkgw...@forum.dlang.org
https://forum.dlang.org/thread/qsayoktyffczskrnm...@forum.dlang.org

To be totally honest, I still don't see what's wrong with just 
creating a new bracket syntax, instead of adding more magic to [] 
(or () for that matter).


Re: Proposal: Object/?? Destruction

2017-10-15 Thread Q. Schroll via Digitalmars-d

On Saturday, 14 October 2017 at 23:20:26 UTC, sarn wrote:

On Saturday, 14 October 2017 at 22:20:46 UTC, Q. Schroll wrote:
Therefore, and because of brackets, you can distinguish f(1, 
2) from f([1, 2]).


But in f([1, 2]), it's ambiguous (just by parsing) whether [1, 
2] is a tuple literal or a dynamic array literal.


It would be a tuple if that's the best match, otherwise 
conversion to int[] is tried. Even today, [1, 2] is ambiguous: Is 
it a static or a dynamic array of int? Is it of type int[2] or 
int[]? The spec says, it depends what you do with it! We can 
progress that and enlarge the int[2] version to [int, int] -- a 
special case of a 2-tuple. It remains the same: If [1, 2] can be 
used as a dynamic array, it will be. If not, the compiler tries a 
static array. With tuples, it would try a tuple. If f has an 
overload taking int[] or something similar, it will treat [1, 2] 
as a dynamic array with homogeneus types. If the objects are not 
compatible, an error occurs like "tuple [..contents..] cannot be 
implicitly converted to T[]". Else, if it has an overload for a 
compatible (length, implicit conversion) tuple, that will be 
taken. Consider

   void f(int[2] v) { } // (1)
   void f(int[ ] v) { } // (2)
Here, f([1, 2]) calls (1) as it is the better match. Yet with
   auto x = [1, 2];
f(x) calls (2) because of strict typing. So while [1, 2] is of 
type int[2] or [int, int] as a tuple, typeof([1, 2]) will still 
yield int[]. You cannot ask the one and only correct type of 
[]-literals as they have more than one type. Even if the values 
are incompatible like [1, "a"], asking typeof([1, "a"]) will 
result in an error, because in typeof deduction, []-literals must 
result in dynamic arrays. This holds for auto, because auto has 
the same rules.

   auto tup = [1, "a"];
must fail. You'd need
   [auto, auto] tup = [1, "a"];
or maybe some shorthand syntax that lowers to this.


You'd need to use a prefix or something to the bracket syntax.
[snip]


I just argued, you don't!

The reason there is no such prefix and not even a function in 
Phobos, is it is a trivial task to make one.

T[n] s(T, size_t n)(T[n] elem ...) { return elem; }
static assert(is(typeof(s(1, 2, 3)) == int[3]));
static assert(is(typeof([1, 2, 3].s) == int[3]));
auto x = s(1, 2, 3);
static assert(is(typeof(x) == int[3]));
auto x = s(1, 2.0, 3);
static assert(is(typeof(x) == double[3]));
Try it yourself. It works fine. Instead of s one would use t or 
tuple to allow incompatible types.


Re: Proposal: Object/?? Destruction

2017-10-14 Thread Steven Schveighoffer via Digitalmars-d

Sorry for waiting so long to respond, I had to think about this a lot...

On 10/12/17 3:05 PM, Timon Gehr wrote:

On 10.10.2017 17:05, Steven Schveighoffer wrote:

On 10/9/17 11:22 AM, Timon Gehr wrote:

On 09.10.2017 01:20, Steven Schveighoffer wrote:


My questioning comes with this:

void bar(int a);
void bar((int,) x);

To me, it is confusing or at least puzzling that these two aren't 
the same.

...


Well, to me it is a bit confusing that this is puzzling to you. Why 
should int be the same as (int,)? It does not make sense to index an 
integer, but (int,) can be indexed with 0 to get an integer.


I understand why (int,) is different from int. What I meant was, why 
can't I *call* a function that takes a single int tuple with a single 
int value?

...


Because this would require a special-case rule that I had not considered 
so far. This is up to discussion though.


I interpreted your question to be: "Why do your proposed rules not lead 
to my expected behaviour?", and not: "Why do your rules not allow 
this?", but it seems I have misinterpreted your question. Sorry for the 
confusion! :)


Not a problem!

Again, I go back to the 2-parameter version. I can call it with 2 
values, or a tuple of 2 values.


With the caveat that those two cases are actually identical, yes.

auto x = (1,"2"); // construct value
f(x); // now call f with value

and

f(1,"2"); // construct tuple and call f with the resulting value

It is like:

auto x = [1,2];
f(x);

and

f([1,2]);

Except that redundant parentheses are optional:
f(1,"2") is exactly equivalent to f((1,"2")) after parsing.

The second expression just adds an additional pair of parentheses around 
f. f(((1,"2"))) is also the same expression for the same reason.


Note that this does not compile:

void f(int a,int b,int c){}
f(1,(2,3));


Right, there is a structural difference here. The 2 and 3 being tied 
together is a piece of information that is lost or different than is 
expected. I get that, and agree with it.




The reason is that I tried to call f with an argument of type 
(int,(int,int)), while it expected an argument of type (int,int,int).


It makes no difference to the callee how I call it, as long as I put 2 
values on the stack.

...


Well, I think it should maybe not be possible to conflate e.g. (int,int) 
and ((int,),(int,)).


This, I'm not 100% sure on. In my mind, the difference between a value 
and a tuple of one element is trivial and negligible. I think they 
should be implicitly convertible between each other. Perhaps they would 
still be mangled differently, but you could still call both with the 
different forms. Sort of like const(int) and int have different 
semantics, but I can call a function with one or the other.


In that sense, perhaps foo(int) and foo((int,)) are different manglings, 
but you can still call either form with either form.



I don't see why it should be different for a single parameter function.
...


I think you are making a strong point here.

To put it another way, in your scheme, what is the benefit to 
overloading a single value function call with a function call that 
takes a single element tuple? When would this be useful?

...


I agree that this is actually not useful.

Note that this means the following code will be accepted also:

void foo(int x,int y,int z){}

foo((1,2,3),);

Does this match your expectation?


Yes, that seems reasonable to me.




Currently, I can call this:

foo(T...)(T t) if (T.length == 1) // function that takes a single 
element tuple


like this:

foo(1);

Why is this disallowed in your tuple scheme?
...


I take this to mean, why does the following code not compile:

void foo(T)(T t) if(T.length == 1) { ... }

foo(1);


Nope, I meant my original. A "tuple" as D currently uses it, can have 
exactly one element, and I can call that function with exactly one 
value. I don't have to call it as:


AliasSeq!(int) v;
v[0] = 1;
foo(v);

Which is analogous to your requirements (obviously, D is missing the 
syntax for tuple literals, which is why it's complicated).


Note that if foo is:

foo(int x);

I can still call it with v. I don't see why we can't keep these kinds 
of allowances.

...


I see. Well, we can't keep them to the extent AliasSeq has them. 
AliasSeq always auto-expands. Auto-expansion for tuples can become a 
problem, especially in generic code, because it forgets structure 
information. For example:


void printElements(T)(T[] arr){
     foreach(x;enumerate(a)){
     print("at index ",x[0]," we have ",x[1]);
     }
}

auto a = [(1,2),(3,4),(5,6)];
printElements(a);

With auto-expansion, this prints:
at index 0, we have 1
at index 1, we have 3
at index 2, we have 5

However, it is quite clear from the definition of printElements that the 
programmer wanted it to print:


at index 0, we have (1,2)
at index 1, we have (3,4)
at index 2, we have (5,6)
AliasSeq does not have this specific problem, because it cannot be put 
into an array without expanding.


Right, 

Re: Proposal: Object/?? Destruction

2017-10-14 Thread sarn via Digitalmars-d

On Saturday, 14 October 2017 at 22:20:46 UTC, Q. Schroll wrote:
Therefore, and because of brackets, you can distinguish f(1, 2) 
from f([1, 2]).


But in f([1, 2]), it's ambiguous (just by parsing) whether [1, 2] 
is a tuple literal or a dynamic array literal.


You'd need to use a prefix or something to the bracket syntax.  
E.g., $[1,2].  The dollar sign is just an example, but it might 
work because currently $ only seems to be used in slice syntax 
and in inline assembly.  I don't think tuple literals are needed 
in inline assembly, and I think the slice syntax might be okay 
because (unlike C) D doesn't allow the borked 0[arr] style of 
indexing, so expressions like arr[0..$[x][y]] are unambiguous.  
(I.e., $[x][y] is the yth element of a tuple containing x, and 
not the yth element of the $th element of x as an array).


Re: Proposal: Object/?? Destruction

2017-10-14 Thread Q. Schroll via Digitalmars-d
I've thought about tuples and stuff for a while. For tuples, I'll 
use [brackets]. Reasons follow.


Homogeneous tuples are repetitions of some single type. We have 
them today in form of static arrays. We could allow 
"inhomogeneous arrays" and call them tuples. T[n] is then an 
alias for [T, T, .., T] with n repititions. In place of a type 
[T, S] means Tuple!(T, S) and in place of an Object [t, s] means 
tuple(t, s). Note that D's grammar allows disambiguate types and 
objects by syntax.


A tuple implicitly converts to some other, if the pointwise types 
do. Bracket literals constitute a separate type that exists in 
the compiler only. We have that already to make

   int[2] a = [ 1, 2 ];
not allocate on the heap, but
   int[]  a = [ 1, 2 ];
does. So at first, [ 1, 2.0 ] is of type [int, double]. If you 
assign it to a double[2], because int -> double, the conversion 
is no problem. The thing that changes, is when you ask for 
typeof([ 1, 2.0 ]) directly. Of course,

   auto tup = [ 1, 2.0 ];
will homogenize the tuple to double[] similar to how it does 
today. Declaration-decomposition can be done as

   auto [a, b] = f(x);
(non-exlusive) or
   [auto a, auto b] = f(x);
The first one is shorter, the latter one let's you do
   [int a, auto b] = f(x);
So auto [x1, .. xn] is just a shorthand for [auto x1, .. auto xn].
Assignment-decomposition is the same with the types/auto missing.
Swap can be done with
   [a, b] = [b, a];
From the type system, if a tuple literal has only lvalues inside, 
it is an lvalue, too.
Note that there must be some way to handle side effects 
correctly. The problem is already known from normal assignment.


1-tuples are in a natural way included. int[1] is today different 
from int. When we have first-class tuples in D, we should not 
distinguish static arrays from homogeneous tuples.


Therefore, and because of brackets, you can distinguish f(1, 2) 
from f([1, 2]). I find the syntax (1,) for 1-tuples weird. 
Parenthesis are used only for operator precedence and function 
calls. They should not be used for tuples -- the 1-tuple case and 
f(1, 2) vs f((1, 2)) prove that. Parenthesis are a tool of 
syntax, not semantics. You can never omit brackets in D.


Maybe you can use some of that as input for your DIP.


Re: Proposal: Object/?? Destruction

2017-10-12 Thread Timon Gehr via Digitalmars-d

On 10.10.2017 17:05, Steven Schveighoffer wrote:

On 10/9/17 11:22 AM, Timon Gehr wrote:

On 09.10.2017 01:20, Steven Schveighoffer wrote:


My questioning comes with this:

void bar(int a);
void bar((int,) x);

To me, it is confusing or at least puzzling that these two aren't the 
same.

...


Well, to me it is a bit confusing that this is puzzling to you. Why 
should int be the same as (int,)? It does not make sense to index an 
integer, but (int,) can be indexed with 0 to get an integer.


I understand why (int,) is different from int. What I meant was, why 
can't I *call* a function that takes a single int tuple with a single 
int value?

...


Because this would require a special-case rule that I had not considered 
so far. This is up to discussion though.


I interpreted your question to be: "Why do your proposed rules not lead 
to my expected behaviour?", and not: "Why do your rules not allow 
this?", but it seems I have misinterpreted your question. Sorry for the 
confusion! :)


It shouldn't matter to the caller whether you plan to fiddle with your 
parameter via tuple syntax or directly with a value.

...


I see. I think what you propose does make sense, as it might smoothen 
out the interaction with other D language features such as variadics and 
overloading.


Again, I go back to the 2-parameter version. I can call it with 2 
values, or a tuple of 2 values.


With the caveat that those two cases are actually identical, yes.

auto x = (1,"2"); // construct value
f(x); // now call f with value

and

f(1,"2"); // construct tuple and call f with the resulting value

It is like:

auto x = [1,2];
f(x);

and

f([1,2]);

Except that redundant parentheses are optional:
f(1,"2") is exactly equivalent to f((1,"2")) after parsing.

The second expression just adds an additional pair of parentheses around 
f. f(((1,"2"))) is also the same expression for the same reason.


Note that this does not compile:

void f(int a,int b,int c){}
f(1,(2,3));

The reason is that I tried to call f with an argument of type 
(int,(int,int)), while it expected an argument of type (int,int,int).


It makes no difference to the callee how 
I call it, as long as I put 2 values on the stack.

...


Well, I think it should maybe not be possible to conflate e.g. (int,int) 
and ((int,),(int,)).



I don't see why it should be different for a single parameter function.
...


I think you are making a strong point here.

To put it another way, in your scheme, what is the benefit to 
overloading a single value function call with a function call that takes 
a single element tuple? When would this be useful?

...


I agree that this is actually not useful.

Note that this means the following code will be accepted also:

void foo(int x,int y,int z){}

foo((1,2,3),);

Does this match your expectation?


Currently, I can call this:

foo(T...)(T t) if (T.length == 1) // function that takes a single 
element tuple


like this:

foo(1);

Why is this disallowed in your tuple scheme?
...


I take this to mean, why does the following code not compile:

void foo(T)(T t) if(T.length == 1) { ... }

foo(1);


Nope, I meant my original. A "tuple" as D currently uses it, can have 
exactly one element, and I can call that function with exactly one 
value. I don't have to call it as:


AliasSeq!(int) v;
v[0] = 1;
foo(v);

Which is analogous to your requirements (obviously, D is missing the 
syntax for tuple literals, which is why it's complicated).


Note that if foo is:

foo(int x);

I can still call it with v. I don't see why we can't keep these kinds of 
allowances.

...


I see. Well, we can't keep them to the extent AliasSeq has them. 
AliasSeq always auto-expands. Auto-expansion for tuples can become a 
problem, especially in generic code, because it forgets structure 
information. For example:


void printElements(T)(T[] arr){
foreach(x;enumerate(a)){
print("at index ",x[0]," we have ",x[1]);
}
}

auto a = [(1,2),(3,4),(5,6)];
printElements(a);

With auto-expansion, this prints:
at index 0, we have 1
at index 1, we have 3
at index 2, we have 5

However, it is quite clear from the definition of printElements that the 
programmer wanted it to print:


at index 0, we have (1,2)
at index 1, we have (3,4)
at index 2, we have (5,6)

AliasSeq does not have this specific problem, because it cannot be put 
into an array without expanding.


I would think single value tuples and single values would be pretty 
much interchangeable.


Well, no. Otherwise 2[0] would be allowed and equal to 2. And then, 
what would [2][0] be? [2] or 2?


Not interchangeable in terms of usage, but interchangeable in terms of 
overloading.


What I would have expected is for foo(int) and foo((int,)) to be 
equivalent mangling (like the bar(int, int) and bar((int, int)) are 
equivalent), and for the caller to be able to call those functions with 
either a single value or a singleton tuple.


Inside the function, of course, they are treated differently as the 

Re: Proposal: Object/?? Destruction

2017-10-10 Thread Steven Schveighoffer via Digitalmars-d

On 10/9/17 11:22 AM, Timon Gehr wrote:

On 09.10.2017 01:20, Steven Schveighoffer wrote:


My questioning comes with this:

void bar(int a);
void bar((int,) x);

To me, it is confusing or at least puzzling that these two aren't the 
same.

...


Well, to me it is a bit confusing that this is puzzling to you. Why 
should int be the same as (int,)? It does not make sense to index an 
integer, but (int,) can be indexed with 0 to get an integer.


I understand why (int,) is different from int. What I meant was, why 
can't I *call* a function that takes a single int tuple with a single 
int value?


It shouldn't matter to the caller whether you plan to fiddle with your 
parameter via tuple syntax or directly with a value.


Again, I go back to the 2-parameter version. I can call it with 2 
values, or a tuple of 2 values. It makes no difference to the callee how 
I call it, as long as I put 2 values on the stack.


I don't see why it should be different for a single parameter function.

To put it another way, in your scheme, what is the benefit to 
overloading a single value function call with a function call that takes 
a single element tuple? When would this be useful?



Currently, I can call this:

foo(T...)(T t) if (T.length == 1) // function that takes a single 
element tuple


like this:

foo(1);

Why is this disallowed in your tuple scheme?
...


I take this to mean, why does the following code not compile:

void foo(T)(T t) if(T.length == 1) { ... }

foo(1);


Nope, I meant my original. A "tuple" as D currently uses it, can have 
exactly one element, and I can call that function with exactly one 
value. I don't have to call it as:


AliasSeq!(int) v;
v[0] = 1;
foo(v);

Which is analogous to your requirements (obviously, D is missing the 
syntax for tuple literals, which is why it's complicated).


Note that if foo is:

foo(int x);

I can still call it with v. I don't see why we can't keep these kinds of 
allowances.


I would think single value tuples and single values would be pretty 
much interchangeable.


Well, no. Otherwise 2[0] would be allowed and equal to 2. And then, what 
would [2][0] be? [2] or 2?


Not interchangeable in terms of usage, but interchangeable in terms of 
overloading.


What I would have expected is for foo(int) and foo((int,)) to be 
equivalent mangling (like the bar(int, int) and bar((int, int)) are 
equivalent), and for the caller to be able to call those functions with 
either a single value or a singleton tuple.


Inside the function, of course, they are treated differently as the 
callee decides whether to unpack the tuple or not via the parameters.


We can also think about adding a "light" version of tuple support, 
that just supports unpacking for library-defined tuple types and 
nothing else, but I'd prefer to have proper tuples.


This flew over my head :)
...


If we cannot have proper tuples, having some syntactic sugar for tuple 
unpacking during variable declaration may still be useful:


import std.typecons;

auto (x,y) = tuple(1,"2");
(int x,string y) = tuple(1,"2");

This is syntactically forward-compatible.


OK, this makes sense, yes.

-Steve


Re: Proposal: Object/?? Destruction

2017-10-09 Thread jmh530 via Digitalmars-d

On Monday, 9 October 2017 at 15:22:35 UTC, Timon Gehr wrote:


Singleton tuples might seem pointless, and some languages do 
not support such single-element tuples, but as we want to 
support slicing, they should probably exist. (Also, we might 
want to create a tuple from an AliasSeq, which can be achieved 
by dropping it into a single-element tuple and letting it 
auto-expand.)




Singleton tuples would be necessary for any kind of recursion on 
tuples.


The way mir.functional.RefTuple works is similar to your AliasSeq 
tuple. This is because it uses anonymous names for the fields. 
std.typecons.Tuple assumes field name/Type pairs.


Re: Proposal: Object/?? Destruction

2017-10-09 Thread Timon Gehr via Digitalmars-d

On 09.10.2017 01:20, Steven Schveighoffer wrote:

On 10/7/17 8:56 PM, Timon Gehr wrote:

On 06.10.2017 23:34, Steven Schveighoffer wrote:




No. All functions take one argument and produce one result. (The 
argument and the result may or may not be a tuple, but there is no 
essential difference between the two cases.) You can match a value 
against a pattern on the function call.


It is weird to me that a function with 2 parameters is the same as a 
function that takes a 2-element tuple, but a function with one 
parameter is not the same as a function that takes a 1-element tuple. 
That is where I feel it's a contradiction.

...
If a function with 2 parameters was the same as a function that takes 
a 2-element tuple, and a function with one parameter that is a 
2-element tuple is the same as a function that takes a 1-element 
tuple, then a function that takes a 2-element tuple is the same as a 
function that takes a 1-element tuple. So I think the opposite is the 
case.


// those two are the same
void foo(int a,string b); // match two-element tuple
void foo((int,string) x); // take two-element tuple w/o matching

// those two are the same
void bar(int a,);   // match one-element tuple
void bar((int,) x); // take one-element tuple w/o matching

This is like:

(int a,string b)=(1,"2"); // match
// vs
(int,string) x=(1,"2"); // w/o matching

and

(int a,)=(1,); // match
// vs
(int,) x=(1,); // w/o matching


My questioning comes with this:

void bar(int a);
void bar((int,) x);

To me, it is confusing or at least puzzling that these two aren't the same.
...


Well, to me it is a bit confusing that this is puzzling to you. Why 
should int be the same as (int,)? It does not make sense to index an 
integer, but (int,) can be indexed with 0 to get an integer.


I believe your difficulty is rather with the notion that what before was 
a function that takes a single value is no longer analogous to what 
before was a function that takes multiple values. The analogy breaks 
because now they are handled precisely the same way, rather than just 
analogously. Furthermore, some existing syntax slightly changes meaning: 
The prior syntax for declaring multiple arguments is now a pattern that 
matches against a single tuple argument.


The new design is more orthogonal and in effect more useful, because 
functions no longer need to care about and interfere with the concept of 
"multiple values".



The first is like a "regular" function that doesn't take a tuple.

The second is a new "tuplized" function that takes a tuple. both take 
one parameter (one version via the regular argument syntax, one via a 
tuplized syntax).


One takes an argument that is an integer. The other takes an argument 
that is a tuple containing a single integer.



Why is it not the same?


One takes an int while the other takes an (int,).

Clearly a tuple of 1 can bind 
to a single value, just like a tuple of 2 can bind to 2 values.

...


But it is precisely what is happening. However, not every value is a 
singleton tuple just by virtue of not being a tuple of multiple values.



Currently, I can call this:

foo(T...)(T t) if (T.length == 1) // function that takes a single 
element tuple


like this:

foo(1);

Why is this disallowed in your tuple scheme?
...


I take this to mean, why does the following code not compile:

void foo(T)(T t) if(T.length == 1) { ... }

foo(1);

This is because T is matched to int, which does not have length.

A few more examples:

void foo(int x);   // foo takes an int
void foo(int x,);  // foo takes an (int,) and matches it against 
(int x,) in order to extract the value x
void foo(int x,int y); // foo takes an (int,int) and matches it against 
(int x,int y) in order to extract the values x and y.


In case this is not convincing to you: Why does your reasoning apply 
to arguments but not return values? Why should arguments not behave 
the same as return values? If it does actually apply to return values: 
what special syntax would you propose for functions that "return 
multiple values"? Is it really reasonable to not use tuples for that?


I don't understand the question.


I'm was trying to figure out what is causing the confusion. I was trying 
to appeal to symmetry to get past what seemed to be your notion that 
there is a significant difference between multiple values and a single 
tuple: If you have a function that needs to return multiple values, you 
return a single tuple. If you have a function that needs to take 
multiple values, you take a single tuple. With tuples, it is sufficient 
to return a single value, and it is also sufficient to take a single 
value as the argument.


I would think single value tuples and 
single values would be pretty much interchangeable.


Well, no. Otherwise 2[0] would be allowed and equal to 2. And then, what 
would [2][0] be? [2] or 2?


It's up to the user 
of the value whether he wants to look at it as a tuple (which has length 
and must be indexed) vs. a 

Re: Proposal: Object/?? Destruction

2017-10-08 Thread Steven Schveighoffer via Digitalmars-d

On 10/7/17 8:56 PM, Timon Gehr wrote:

On 06.10.2017 23:34, Steven Schveighoffer wrote:




No. All functions take one argument and produce one result. (The 
argument and the result may or may not be a tuple, but there is no 
essential difference between the two cases.) You can match a value 
against a pattern on the function call.


It is weird to me that a function with 2 parameters is the same as a 
function that takes a 2-element tuple, but a function with one 
parameter is not the same as a function that takes a 1-element tuple. 
That is where I feel it's a contradiction.

...
If a function with 2 parameters was the same as a function that takes a 
2-element tuple, and a function with one parameter that is a 2-element 
tuple is the same as a function that takes a 1-element tuple, then a 
function that takes a 2-element tuple is the same as a function that 
takes a 1-element tuple. So I think the opposite is the case.


// those two are the same
void foo(int a,string b); // match two-element tuple
void foo((int,string) x); // take two-element tuple w/o matching

// those two are the same
void bar(int a,);   // match one-element tuple
void bar((int,) x); // take one-element tuple w/o matching

This is like:

(int a,string b)=(1,"2"); // match
// vs
(int,string) x=(1,"2"); // w/o matching

and

(int a,)=(1,); // match
// vs
(int,) x=(1,); // w/o matching


My questioning comes with this:

void bar(int a);
void bar((int,) x);

To me, it is confusing or at least puzzling that these two aren't the same.

The first is like a "regular" function that doesn't take a tuple.

The second is a new "tuplized" function that takes a tuple. both take 
one parameter (one version via the regular argument syntax, one via a 
tuplized syntax). Why is it not the same? Clearly a tuple of 1 can bind 
to a single value, just like a tuple of 2 can bind to 2 values.


Currently, I can call this:

foo(T...)(T t) if (T.length == 1) // function that takes a single 
element tuple


like this:

foo(1);

Why is this disallowed in your tuple scheme?

In case this is not convincing to you: Why does your reasoning apply to 
arguments but not return values? Why should arguments not behave the 
same as return values? If it does actually apply to return values: what 
special syntax would you propose for functions that "return multiple 
values"? Is it really reasonable to not use tuples for that?


I don't understand the question. I would think single value tuples and 
single values would be pretty much interchangeable. It's up to the user 
of the value whether he wants to look at it as a tuple (which has length 
and must be indexed) vs. a single value.


Right, but cases where T is expected to match to exactly one type will 
now match with multiple types. It messes up is(typeof(...)) checks.




All new language features can be detected using is(typeof(...)) this is 
usually ignored for language evolution. We'd need to check how much code 
relies on this specific case not compiling.


I definitely don't have an answer off hand, but I wouldn't be surprised 
if this broke at least some code in phobos.


We can also think about adding a "light" version of tuple support, that 
just supports unpacking for library-defined tuple types and nothing 
else, but I'd prefer to have proper tuples.


This flew over my head :)

-Steve


Re: Proposal: Object/?? Destruction

2017-10-07 Thread Timon Gehr via Digitalmars-d

On 06.10.2017 23:34, Steven Schveighoffer wrote:




No. All functions take one argument and produce one result. (The 
argument and the result may or may not be a tuple, but there is no 
essential difference between the two cases.) You can match a value 
against a pattern on the function call.


It is weird to me that a function with 2 parameters is the same as a 
function that takes a 2-element tuple, but a function with one parameter 
is not the same as a function that takes a 1-element tuple. That is 
where I feel it's a contradiction.

...
If a function with 2 parameters was the same as a function that takes a 
2-element tuple, and a function with one parameter that is a 2-element 
tuple is the same as a function that takes a 1-element tuple, then a 
function that takes a 2-element tuple is the same as a function that 
takes a 1-element tuple. So I think the opposite is the case.


// those two are the same
void foo(int a,string b); // match two-element tuple
void foo((int,string) x); // take two-element tuple w/o matching

// those two are the same
void bar(int a,);   // match one-element tuple
void bar((int,) x); // take one-element tuple w/o matching

This is like:

(int a,string b)=(1,"2"); // match
// vs
(int,string) x=(1,"2"); // w/o matching

and

(int a,)=(1,); // match
// vs
(int,) x=(1,); // w/o matching

In case this is not convincing to you: Why does your reasoning apply to 
arguments but not return values? Why should arguments not behave the 
same as return values? If it does actually apply to return values: what 
special syntax would you propose for functions that "return multiple 
values"? Is it really reasonable to not use tuples for that?


This would mess up a TON of code. I can say for certain, a single 
type argument can never be made to accept a tuple.


The proposal is to make all arguments "single type arguments". The 
"single type" might be a tuple. A tuple type is just a type, after 
all. For two current functions where only one matches but after the 
change both would match, the same one would still be selected, because 
it is more specialized.


Right, but cases where T is expected to match to exactly one type will 
now match with multiple types. It messes up is(typeof(...)) checks.


-Steve


All new language features can be detected using is(typeof(...)) this is 
usually ignored for language evolution. We'd need to check how much code 
relies on this specific case not compiling.


We can also think about adding a "light" version of tuple support, that 
just supports unpacking for library-defined tuple types and nothing 
else, but I'd prefer to have proper tuples.


Re: Proposal: Object/?? Destruction

2017-10-06 Thread Steven Schveighoffer via Digitalmars-d

On 10/6/17 3:31 PM, Timon Gehr wrote:

On 06.10.2017 14:26, Steven Schveighoffer wrote:

On 10/5/17 3:42 PM, Timon Gehr wrote:

On 05.10.2017 17:40, Steven Schveighoffer wrote:

On 10/5/17 2:42 AM, Timon Gehr wrote:

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. 
My favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


I know you have an answer for this, but pardon my ignorance.


I indeed have strong opinions on how to do this correctly, as I have 
given some thought to it when designing the (still quite basic) type 
system of PSI: https://github.com/eth-srl/psi


The idea is to follow type theory/mathematics where the type of 
functions is a binary type constructor taking domain and codomain to 
the type of functions mapping values from the domain to values from 
the codomain. Multiple function arguments are just the function 
applied to a tuple of values.



Why isn't (a) good enough?



typeof((a)) should be typeof(a). This is just a parenthesized 
expression, as in (a+b)*c.


Right, I agree.


typeof((a,)) should be (typeof(a),).


I guess my question is more in the context of the problem at hand:

int foo();

auto (a) = foo();

why can't this work?
...


This could be made to compile, but this is not really about tuples.

But then of course, it shouldn't work, because int is not a tuple. So 
I suppose I have answered my own question -- we need a way to specify 
a tuple of one for prototype foo!


Indeed, my experience with tuples and their usage is quite limited.

Even though the syntax is straightforward and unambiguous, it looks 
incorrect, like you forgot something.

...


That's not necessarily bad. (When is the last time you have used a 
singleton tuple?)


I'm not an expert in language design, but would it be worth exploring 
other punctuation that isn't used in the language currently to allow 
better syntax? It seems like the trailing comma is to get around 
ambiguity,


It's the comma that indicates tupling, so there is not really ambiguity, 
the expression (a) just is not a tuple. To indicate a tuple you need to 
use the tupling operator ','. Trailing commas are allowed for all 
tuples, but for singleton tuples they are also necessary.


but there would be no ambiguity if you used something other than 
current punctuation to surround the tuple.


Angle brackets come to mind .


D avoids angle brackets.

Also you could use a leading symbol to change the meaning of the 
parentheses, like $(a).

...


This is very noisy, and once you go with non-standard tuple syntax, you 
can just as well use tuple(a).



---
(int,) foo(int a){ return (a,); } // turn value into singleton tuple
int bar(int a,){ return a[0]; }   // turn singleton tuple into value

void main(){
 foo(2,); // error: cannot convert (int,) to int
 bar(2); // error: cannot convert int to (int,)
 auto (x,) = foo(2); // ok, x has type int
 auto y = bar(2,); // ok y has type int
 auto z = foo(2); // ok, z has type (int,)
}
---

---
// The following two function signatures are equivalent (identical 
name mangling):

(int,string) foo(int a,string b){
 return (a,b);
}

(int,string) foo((int,string) x){
 return x;
}
---


So I will ask, what is the usage of foo here?

In the first example (foo and bar), you can't call a function that 
takes a tuple with a single value, and you can't call a function that 
takes a value with a single tuple (BTW, this is not how AliasSeq 
works, you can call functions that take a single arg with single 
element tuples).

...


AliasSeq auto-expands. If you call a function with a single element 
AliasSeq, it will expand to a single value and not be an AliasSeq 
anymore. Built-in tuples should not auto-expand, so a singleton tuple 
stays a singleton tuple (they will have an explicit .expand property).


In your second example, where foo takes a 2-element tuple or 2 values, 


All functions take a single value. That value might be a tuple. (Of 
course, we will continue to say that a function can take multiple 
arguments, because it is convenient, but what this _means_ is that it 
takes a single tuple argument.)


you say the name mangling is equivalent. Does that mean if I only 
define the tuple version, I can call it with foo(1, "hello") and vice 
versa? 


Yes. (Both options are "the tuple version".)


This seems to contradict your example above.
...


No. All functions take one argument and produce one result. (The 
argument and the result may or may not be a tuple, but there is no 
essential difference between the two cases.) You can match a value 
against a pattern on the function call.


It is weird to me that a function with 2 parameters is the same as a 
function that takes a 2-element tuple, but a function with one parameter 
is not the same as a function that takes a 

Re: Proposal: Object/?? Destruction

2017-10-06 Thread jmh530 via Digitalmars-d

On Friday, 6 October 2017 at 19:51:39 UTC, Timon Gehr wrote:
No, under my thinking the original example should have been 
what it was.
Enclosing an expression in an additional set of parentheses 
does not change its semantics. This is true even if one set of 
parentheses is part of the function call.


Hmm, I hadn't realized that you can have multiple sets of 
parentheses without error. I was assuming you would treat the 
second set as a tuple.


Re: Proposal: Object/?? Destruction

2017-10-06 Thread Timon Gehr via Digitalmars-d

On 06.10.2017 21:43, jmh530 wrote:

On Friday, 6 October 2017 at 19:31:11 UTC, Timon Gehr wrote:
The proposal is to make all arguments "single type arguments". The 
"single type" might be a tuple. A tuple type is just a type, after 
all. For two current functions where only one matches but after the 
change both would match, the same one would still be selected, because 
it is more specialized.


[snip]
Then the call foo(2) will still go to the first overload and the call 
foo(1,2) will still go to the second overload, while the call 
foo(1,2,3) will still go to the third overload.



So under your thinking, the original example should have been something 
like:


---
auto id(T)(T x){ return x; }

void main(){
     auto a = id(2); // ok, a is 2.
     auto b = id(1,2); // error, b is not single type argument
     auto c = id(1,); // ok, c is 1.
     auto d = id((1,2)); // ok, d is (1,2)
     auto e = id((1,)); // ok, e is (1,)
}
---


No, under my thinking the original example should have been what it was.
Enclosing an expression in an additional set of parentheses does not 
change its semantics. This is true even if one set of parentheses is 
part of the function call.


Re: Proposal: Object/?? Destruction

2017-10-06 Thread jmh530 via Digitalmars-d

On Friday, 6 October 2017 at 19:31:11 UTC, Timon Gehr wrote:
The proposal is to make all arguments "single type arguments". 
The "single type" might be a tuple. A tuple type is just a 
type, after all. For two current functions where only one 
matches but after the change both would match, the same one 
would still be selected, because it is more specialized.


[snip]
Then the call foo(2) will still go to the first overload and 
the call foo(1,2) will still go to the second overload, while 
the call foo(1,2,3) will still go to the third overload.



So under your thinking, the original example should have been 
something like:


---
auto id(T)(T x){ return x; }

void main(){
auto a = id(2); // ok, a is 2.
auto b = id(1,2); // error, b is not single type argument
auto c = id(1,); // ok, c is 1.
auto d = id((1,2)); // ok, d is (1,2)
auto e = id((1,)); // ok, e is (1,)
}
---


Re: Proposal: Object/?? Destruction

2017-10-06 Thread Timon Gehr via Digitalmars-d

On 06.10.2017 14:26, Steven Schveighoffer wrote:

On 10/5/17 3:42 PM, Timon Gehr wrote:

On 05.10.2017 17:40, Steven Schveighoffer wrote:

On 10/5/17 2:42 AM, Timon Gehr wrote:

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. 
My favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


I know you have an answer for this, but pardon my ignorance.


I indeed have strong opinions on how to do this correctly, as I have 
given some thought to it when designing the (still quite basic) type 
system of PSI: https://github.com/eth-srl/psi


The idea is to follow type theory/mathematics where the type of 
functions is a binary type constructor taking domain and codomain to 
the type of functions mapping values from the domain to values from 
the codomain. Multiple function arguments are just the function 
applied to a tuple of values.



Why isn't (a) good enough?



typeof((a)) should be typeof(a). This is just a parenthesized 
expression, as in (a+b)*c.


Right, I agree.


typeof((a,)) should be (typeof(a),).


I guess my question is more in the context of the problem at hand:

int foo();

auto (a) = foo();

why can't this work?
...


This could be made to compile, but this is not really about tuples.

But then of course, it shouldn't work, because int is not a tuple. So I 
suppose I have answered my own question -- we need a way to specify a 
tuple of one for prototype foo!


Indeed, my experience with tuples and their usage is quite limited.

Even though the syntax is straightforward and unambiguous, it looks 
incorrect, like you forgot something.

...


That's not necessarily bad. (When is the last time you have used a 
singleton tuple?)


I'm not an expert in language design, but would it be worth exploring 
other punctuation that isn't used in the language currently to allow 
better syntax? It seems like the trailing comma is to get around 
ambiguity,


It's the comma that indicates tupling, so there is not really ambiguity, 
the expression (a) just is not a tuple. To indicate a tuple you need to 
use the tupling operator ','. Trailing commas are allowed for all 
tuples, but for singleton tuples they are also necessary.


but there would be no ambiguity if you used something other 
than current punctuation to surround the tuple.


Angle brackets come to mind .


D avoids angle brackets.

Also you could use a leading symbol to 
change the meaning of the parentheses, like $(a).

...


This is very noisy, and once you go with non-standard tuple syntax, you 
can just as well use tuple(a).



---
(int,) foo(int a){ return (a,); } // turn value into singleton tuple
int bar(int a,){ return a[0]; }   // turn singleton tuple into value

void main(){
 foo(2,); // error: cannot convert (int,) to int
 bar(2); // error: cannot convert int to (int,)
 auto (x,) = foo(2); // ok, x has type int
 auto y = bar(2,); // ok y has type int
 auto z = foo(2); // ok, z has type (int,)
}
---

---
// The following two function signatures are equivalent (identical 
name mangling):

(int,string) foo(int a,string b){
 return (a,b);
}

(int,string) foo((int,string) x){
 return x;
}
---


So I will ask, what is the usage of foo here?

In the first example (foo and bar), you can't call a function that takes 
a tuple with a single value, and you can't call a function that takes a 
value with a single tuple (BTW, this is not how AliasSeq works, you can 
call functions that take a single arg with single element tuples).

...


AliasSeq auto-expands. If you call a function with a single element 
AliasSeq, it will expand to a single value and not be an AliasSeq 
anymore. Built-in tuples should not auto-expand, so a singleton tuple 
stays a singleton tuple (they will have an explicit .expand property).


In your second example, where foo takes a 2-element tuple or 2 values, 


All functions take a single value. That value might be a tuple. (Of 
course, we will continue to say that a function can take multiple 
arguments, because it is convenient, but what this _means_ is that it 
takes a single tuple argument.)


you say the name mangling is equivalent. Does that mean if I only define 
the tuple version, I can call it with foo(1, "hello") and vice versa? 


Yes. (Both options are "the tuple version".)


This seems to contradict your example above.
...


No. All functions take one argument and produce one result. (The 
argument and the result may or may not be a tuple, but there is no 
essential difference between the two cases.) You can match a value 
against a pattern on the function call. The following are equivalent:


(int,string) foo(){
// unpack at initialization of local variables of `foo`
// pattern: (int a, string b)
// value:   (1,"2")
(int a, string b) = (1,"2");
return (a,b);
}


Re: Proposal: Object/?? Destruction

2017-10-06 Thread Steven Schveighoffer via Digitalmars-d

On 10/5/17 3:42 PM, Timon Gehr wrote:

On 05.10.2017 17:40, Steven Schveighoffer wrote:

On 10/5/17 2:42 AM, Timon Gehr wrote:

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


I know you have an answer for this, but pardon my ignorance.


I indeed have strong opinions on how to do this correctly, as I have 
given some thought to it when designing the (still quite basic) type 
system of PSI: https://github.com/eth-srl/psi


The idea is to follow type theory/mathematics where the type of 
functions is a binary type constructor taking domain and codomain to the 
type of functions mapping values from the domain to values from the 
codomain. Multiple function arguments are just the function applied to a 
tuple of values.



Why isn't (a) good enough?



typeof((a)) should be typeof(a). This is just a parenthesized 
expression, as in (a+b)*c.


Right, I agree.


typeof((a,)) should be (typeof(a),).


I guess my question is more in the context of the problem at hand:

int foo();

auto (a) = foo();

why can't this work?

But then of course, it shouldn't work, because int is not a tuple. So I 
suppose I have answered my own question -- we need a way to specify a 
tuple of one for prototype foo!


Indeed, my experience with tuples and their usage is quite limited.

Even though the syntax is straightforward and unambiguous, it looks 
incorrect, like you forgot something.


I'm not an expert in language design, but would it be worth exploring 
other punctuation that isn't used in the language currently to allow 
better syntax? It seems like the trailing comma is to get around 
ambiguity, but there would be no ambiguity if you used something other 
than current punctuation to surround the tuple.


Angle brackets come to mind . Also you could use a leading symbol to 
change the meaning of the parentheses, like $(a).



---
(int,) foo(int a){ return (a,); } // turn value into singleton tuple
int bar(int a,){ return a[0]; }   // turn singleton tuple into value

void main(){
     foo(2,); // error: cannot convert (int,) to int
     bar(2); // error: cannot convert int to (int,)
     auto (x,) = foo(2); // ok, x has type int
     auto y = bar(2,); // ok y has type int
     auto z = foo(2); // ok, z has type (int,)
}
---

---
// The following two function signatures are equivalent (identical name 
mangling):

(int,string) foo(int a,string b){
     return (a,b);
}

(int,string) foo((int,string) x){
     return x;
}
---


So I will ask, what is the usage of foo here?

In the first example (foo and bar), you can't call a function that takes 
a tuple with a single value, and you can't call a function that takes a 
value with a single tuple (BTW, this is not how AliasSeq works, you can 
call functions that take a single arg with single element tuples).


In your second example, where foo takes a 2-element tuple or 2 values, 
you say the name mangling is equivalent. Does that mean if I only define 
the tuple version, I can call it with foo(1, "hello") and vice versa? 
This seems to contradict your example above.



---
auto id(T)(T x){ return x; }

void main(){
     auto a = id(2); // ok, a is 2.
     auto b = id(1,2); // ok, b is (1,2)
     auto c = id(1,); // ok, c is (1,)
}
---



This would mess up a TON of code. I can say for certain, a single type 
argument can never be made to accept a tuple.


-Steve


Re: Proposal: Object/?? Destruction

2017-10-05 Thread sarn via Digitalmars-d

On Thursday, 5 October 2017 at 15:23:26 UTC, Seb wrote:
I think I can state the opinion of many D users here: I don't 
mind whether it will be curly braces or round parentheses - the 
important thing is that we will be able to use it in the 
foreseeable future :)
All my +1s.  Let's leave syntax details to people who know the D 
grammar inside out.


Re: Proposal: Object/?? Destruction

2017-10-05 Thread jmh530 via Digitalmars-d

On Thursday, 5 October 2017 at 19:55:15 UTC, Timon Gehr wrote:


The reason why back then it seemed as if it "can't be used" is 
that it was taken by the comma operator. This is no longer the 
case.


Fair enough. I only didn't have an issue with it because I had 
recalled it when reading the previous DIP.


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Timon Gehr via Digitalmars-d

On 05.10.2017 17:48, jmh530 wrote:

On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:


Why curly braces? Multiple function arguments are a form of built-in 
tuple, so the syntax should be consistent:


auto (success, message) = callVoldemortFunction();

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


The curly bracket syntax looks straight out of DIP 32

https://wiki.dlang.org/DIP32
auto {x, y} = {1, "hi"};.


There are many good ideas in DIP32, including this one:


Basic () syntax, perhaps the cleanest, but can't be used:


import std.stdio, std.algorithm, std.container, std.array;

auto encode(T)(Group!("a == b", T[]) sf) {
auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};

while (heap.length > 1) {
auto (lof, loa) = heap.front;  heap.removeFront;
auto (hif, hia) = heap.front;  heap.removeFront;
foreach ((_, ref e); loa) e = '0' ~ e;
foreach ((_, ref e); hia) e = '1' ~ e;
heap.insert((lof + hif, loa ~ hia));
}
return heap.front[1].schwartzSort!((c, e) => (e.length, c));
}

void main() {
auto s = "this is an example for huffman encoding"d;
foreach ((c, e); s.dup.sort().release.group.encode)
writefln("'%s'  %s", c, e);
}
---


The reason why back then it seemed as if it "can't be used" is that it 
was taken by the comma operator. This is no longer the case.


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Timon Gehr via Digitalmars-d

On 05.10.2017 17:23, Seb wrote:


auto {success, message} = callVoldermortFunction();

  This is concept is used in Kotlin. JavaScript es6 takes it even 
further (function parameters and arguments support object destruction)





Why curly braces? Multiple function arguments are a form of built-in 
tuple, so the syntax should be consistent:


auto (success, message) = callVoldemortFunction();



I think I can state the opinion of many D users here: I don't mind 
whether it will be curly braces or round parentheses - the important 
thing is that we will be able to use it in the foreseeable future :)


The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


+1


I'll create a DIP as soon as I can.


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Timon Gehr via Digitalmars-d

On 05.10.2017 17:40, Steven Schveighoffer wrote:

On 10/5/17 2:42 AM, Timon Gehr wrote:

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already 
accepted as a function argument list. I think it is worth breaking 
though. Maybe we should deprecate it.


I know you have an answer for this, but pardon my ignorance.


I indeed have strong opinions on how to do this correctly, as I have 
given some thought to it when designing the (still quite basic) type 
system of PSI: https://github.com/eth-srl/psi


The idea is to follow type theory/mathematics where the type of 
functions is a binary type constructor taking domain and codomain to the 
type of functions mapping values from the domain to values from the 
codomain. Multiple function arguments are just the function applied to a 
tuple of values.



Why isn't (a) good enough?

-Steve


typeof((a)) should be typeof(a). This is just a parenthesized 
expression, as in (a+b)*c.


typeof((a,)) should be (typeof(a),).

(I'm not super keen on conflating the type of a tuple with a tuple of 
types, but this has precedent in alias sequences, and I think it will be 
intuitive to most D users. FWIW, Haskell also does this.)


My intention is to disentangle the concepts "function argument" and 
"multiple values" as much as possible.


For example:

---
(int,string,double) foo(int a,string b,double c){
return (a,b,c);
}

(int,string) bar(int a,string b,double c){
return (a,b);
}

void main(){
auto x = foo(1,"2",3.0); // ok, typeof(x) is (int,string double)
//  ^^^
// syntax of function argument is the same as the
// syntax for a free-standing tuple:
auto y = (1,"2",3.0);

// all functions take a single argument, so you can construct
// the tuple either at the call site, or before that:
(int a,string b,double c) = foo(y); // ok
auto (x,y,z) = foo(a,b,c); // ok

// This allows natural composition of functions.
// It is like DIP 35 except better:
writeln([(1,"2",3.0), (4,"5",6.0)].map!foo.map!bar);
}
---

---
(int,) foo(int a){ return (a,); } // turn value into singleton tuple
int bar(int a,){ return a[0]; }   // turn singleton tuple into value

void main(){
foo(2,); // error: cannot convert (int,) to int
bar(2); // error: cannot convert int to (int,)
auto (x,) = foo(2); // ok, x has type int
auto y = bar(2,); // ok y has type int
auto z = foo(2); // ok, z has type (int,)
}
---

---
// The following two function signatures are equivalent (identical name 
mangling):

(int,string) foo(int a,string b){
return (a,b);
}

(int,string) foo((int,string) x){
return x;
}
---

---
auto id(T)(T x){ return x; }

void main(){
auto a = id(2); // ok, a is 2.
auto b = id(1,2); // ok, b is (1,2)
auto c = id(1,); // ok, c is (1,)
}
---



Re: Proposal: Object/?? Destruction

2017-10-05 Thread jmh530 via Digitalmars-d

On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:


Why curly braces? Multiple function arguments are a form of 
built-in tuple, so the syntax should be consistent:


auto (success, message) = callVoldemortFunction();

The only unresolved question is (as using the result of the 
comma operator has been deprecated already): How to write a 
unary tuple. My favourite is what python does: "(3,)". This is 
however already accepted as a function argument list. I think 
it is worth breaking though. Maybe we should deprecate it.


The curly bracket syntax looks straight out of DIP 32

https://wiki.dlang.org/DIP32
auto {x, y} = {1, "hi"};.


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Steven Schveighoffer via Digitalmars-d

On 10/5/17 2:42 AM, Timon Gehr wrote:

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already accepted 
as a function argument list. I think it is worth breaking though. Maybe 
we should deprecate it.


I know you have an answer for this, but pardon my ignorance. Why isn't 
(a) good enough?


-Steve


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Seb via Digitalmars-d

On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:

On 04.10.2017 12:03, aberba wrote:

  Upon reading this, It triggered an idea.


On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
Marler wrote:

[...]


DIP reminds me of object destruction.

/* extracts success & message from returned type. Could be 
tuple or structure, etc. May even eliminate use of tuples for 
multiple return

*/

auto {success, message} = callVoldermortFunction();

  This is concept is used in Kotlin. JavaScript es6 takes it 
even further (function parameters and arguments support object 
destruction)





Why curly braces? Multiple function arguments are a form of 
built-in tuple, so the syntax should be consistent:


auto (success, message) = callVoldemortFunction();



I think I can state the opinion of many D users here: I don't 
mind whether it will be curly braces or round parentheses - the 
important thing is that we will be able to use it in the 
foreseeable future :)


The only unresolved question is (as using the result of the 
comma operator has been deprecated already): How to write a 
unary tuple. My favourite is what python does: "(3,)". This is 
however already accepted as a function argument list. I think 
it is worth breaking though. Maybe we should deprecate it.


+1


Re: Proposal: Object/?? Destruction

2017-10-05 Thread Timon Gehr via Digitalmars-d

On 04.10.2017 12:03, aberba wrote:

  Upon reading this, It triggered an idea.


On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler wrote:

https://wiki.dlang.org/DIP88

I'd like to see DIP88 (Named Parameters) revived.  Was this proposal 
rejected or is it just stale and needs a refresh? Named parameters 
can be implemented in a library, however, in my opinion they are 
useful enough to warrant a clean syntax with language support.  I'd 
be willing to refresh the DIP so long as I know the idea has not 
already been rejected.


DIP reminds me of object destruction.

/* extracts success & message from returned type. Could be tuple or 
structure, etc. May even eliminate use of tuples for multiple return

*/

auto {success, message} = callVoldermortFunction();

  This is concept is used in Kotlin. JavaScript es6 takes it even 
further (function parameters and arguments support object destruction)





Why curly braces? Multiple function arguments are a form of built-in 
tuple, so the syntax should be consistent:


auto (success, message) = callVoldemortFunction();

The only unresolved question is (as using the result of the comma 
operator has been deprecated already): How to write a unary tuple. My 
favourite is what python does: "(3,)". This is however already accepted 
as a function argument list. I think it is worth breaking though. Maybe 
we should deprecate it.


Re: Proposal: Object/?? Destruction

2017-10-04 Thread aberba via Digitalmars-d

On Wednesday, 4 October 2017 at 12:06:43 UTC, John Colvin wrote:

On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:

 Upon reading this, It triggered an idea.


People often call this "destructuring" or "unpacking" to avoid 
confusion with destructors.


Thats the word I was looking for. Ha ha


Re: Proposal: Object/?? Destruction

2017-10-04 Thread Ali Çehreli via Digitalmars-d

On 10/04/2017 05:06 AM, John Colvin wrote:

> People often call this "destructuring"

Thanks! Now it makes sense. :)

Ali



Re: Proposal: Object/?? Destruction

2017-10-04 Thread bitwise via Digitalmars-d

On Wednesday, 4 October 2017 at 12:06:43 UTC, John Colvin wrote:

[...]

People often call this "destructuring" or "unpacking" to avoid 
confusion with destructors.


Or "Structured Bindings" ;)
http://en.cppreference.com/w/cpp/language/structured_binding




Re: Proposal: Object/?? Destruction

2017-10-04 Thread John Colvin via Digitalmars-d

On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:

 Upon reading this, It triggered an idea.


On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
Marler wrote:

https://wiki.dlang.org/DIP88

I'd like to see DIP88 (Named Parameters) revived.  Was this 
proposal rejected or is it just stale and needs a refresh?  
Named parameters can be implemented in a library, however, in 
my opinion they are useful enough to warrant a clean syntax 
with language support.  I'd be willing to refresh the DIP so 
long as I know the idea has not already been rejected.


DIP reminds me of object destruction.

/* extracts success & message from returned type. Could be 
tuple or structure, etc. May even eliminate use of tuples for 
multiple return

*/

auto {success, message} = callVoldermortFunction();

 This is concept is used in Kotlin. JavaScript es6 takes it 
even further (function parameters and arguments support object 
destruction)


People often call this "destructuring" or "unpacking" to avoid 
confusion with destructors.


Re: Proposal: Object/?? Destruction

2017-10-04 Thread SrMordred via Digitalmars-d

On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:

 Upon reading this, It triggered an idea.


On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
Marler wrote:

[...]


DIP reminds me of object destruction.

/* extracts success & message from returned type. Could be 
tuple or structure, etc. May even eliminate use of tuples for 
multiple return

*/

auto {success, message} = callVoldermortFunction();

 This is concept is used in Kotlin. JavaScript es6 takes it 
even further (function parameters and arguments support object 
destruction)


+1


Re: Proposal: Object/?? Destruction

2017-10-04 Thread Ilya Yaroshenko via Digitalmars-d

On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:

auto {success, message} = callVoldermortFunction();


❤ I want this syntax, plz! This solves the issue how to 
return multiple ref values. --Ilya




Proposal: Object/?? Destruction

2017-10-04 Thread aberba via Digitalmars-d

 Upon reading this, It triggered an idea.


On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler 
wrote:

https://wiki.dlang.org/DIP88

I'd like to see DIP88 (Named Parameters) revived.  Was this 
proposal rejected or is it just stale and needs a refresh?  
Named parameters can be implemented in a library, however, in 
my opinion they are useful enough to warrant a clean syntax 
with language support.  I'd be willing to refresh the DIP so 
long as I know the idea has not already been rejected.


DIP reminds me of object destruction.

/* extracts success & message from returned type. Could be tuple 
or structure, etc. May even eliminate use of tuples for multiple 
return

*/

auto {success, message} = callVoldermortFunction();

 This is concept is used in Kotlin. JavaScript es6 takes it even 
further (function parameters and arguments support object 
destruction)





Re: Proposal: Object/?? Destruction

2017-10-04 Thread aberba via Digitalmars-d-announce

On Wednesday, 4 October 2017 at 09:52:39 UTC, aberba wrote:

Upon reading this, It triggered an idea.

On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler 
wrote:

[...]


Upon reading the DIP, it reminds me of object destruction.

// extracts success & message from returned type. Could be 
tuple or structure, etc. May even eliminate use of tuples for 
multiple return


auto {success, message} = callVoldermortFunction();

This is concept is used in Kotlin. JavaScript es6 takes it even 
further (function parameters and arguments support object 
destruction)


Oops. Wrong place. Will repost in general.


Proposal: Object/?? Destruction

2017-10-04 Thread aberba via Digitalmars-d-announce

Upon reading this, It triggered an idea.

On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler 
wrote:

https://wiki.dlang.org/DIP88

I'd like to see DIP88 (Named Parameters) revived.  Was this 
proposal rejected or is it just stale and needs a refresh?  
Named parameters can be implemented in a library, however, in 
my opinion they are useful enough to warrant a clean syntax 
with language support.  I'd be willing to refresh the DIP so 
long as I know the idea has not already been rejected.


Upon reading the DIP, it reminds me of object destruction.

// extracts success & message from returned type. Could be tuple 
or structure, etc. May even eliminate use of tuples for multiple 
return


auto {success, message} = callVoldermortFunction();

This is concept is used in Kotlin. JavaScript es6 takes it even 
further (function parameters and arguments support object 
destruction)