www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Type inference and overloaded functions

reply "FreeSlave" <freeslave93 gmail.com> writes:
I just found weird D behavior about inference of array types.

Let's suppose we have these overloaded functions:

import std.stdio;

void bar(const(int[3]) arr)
{
     writeln("static array");
}

void bar(const(int[]) arr)
{
     writeln("array slice");
}

// In main we have something like that:
int main(string[] args)
{
     bar([1,2,3]);
     writeln(typeof([1,2,3]).stringof);
     return 0;
}

Weird thing is that the static array version of bar is called, 
but typeof().stringof is int[], not int[3].
Dec 09 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array types.
 
 Let's suppose we have these overloaded functions:
 
 import std.stdio;
 
 void bar(const(int[3]) arr)
 {
      writeln("static array");
 }
 
 void bar(const(int[]) arr)
 {
      writeln("array slice");
 }
 
 // In main we have something like that:
 int main(string[] args)
 {
      bar([1,2,3]);
      writeln(typeof([1,2,3]).stringof);
      return 0;
 }
 
 Weird thing is that the static array version of bar is called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
Dec 09 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array types.

 Let's suppose we have these overloaded functions:

 import std.stdio;

 void bar(const(int[3]) arr)
 {
       writeln("static array");
 }

 void bar(const(int[]) arr)
 {
       writeln("array slice");
 }

 // In main we have something like that:
 int main(string[] args)
 {
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
 }

 Weird thing is that the static array version of bar is called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
The original question is valid then: [1,2,3] goes to the static array overload. Ali
Dec 09 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, December 09, 2013 22:59:49 Ali Çehreli wrote:
 On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array types.
 
 Let's suppose we have these overloaded functions:
 
 import std.stdio;
 
 void bar(const(int[3]) arr)
 {
 
       writeln("static array");
 
 }
 
 void bar(const(int[]) arr)
 {
 
       writeln("array slice");
 
 }
 
 // In main we have something like that:
 int main(string[] args)
 {
 
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
 
 }
 
 Weird thing is that the static array version of bar is called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
The original question is valid then: [1,2,3] goes to the static array overload.
Then AFAIK, that's a bug. The type of array literals is always a dynamic array, so they should match dynamic array overloads rather than static array overloads, or if they match both due to an implicit conversion, there should be an ambiguity error. Choosing the static array overload over the dynamic one is just plain wrong. - Jonathan M Davis
Dec 09 2013
next sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Tuesday, 10 December 2013 at 07:15:43 UTC, Jonathan M Davis 
wrote:
 On Monday, December 09, 2013 22:59:49 Ali Çehreli wrote:
 On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array 
 types.
 
 Let's suppose we have these overloaded functions:
 
 import std.stdio;
 
 void bar(const(int[3]) arr)
 {
 
       writeln("static array");
 
 }
 
 void bar(const(int[]) arr)
 {
 
       writeln("array slice");
 
 }
 
 // In main we have something like that:
 int main(string[] args)
 {
 
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
 
 }
 
 Weird thing is that the static array version of bar is 
 called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
The original question is valid then: [1,2,3] goes to the static array overload.
Then AFAIK, that's a bug. The type of array literals is always a dynamic array, so they should match dynamic array overloads rather than static array overloads, or if they match both due to an implicit conversion, there should be an ambiguity error. Choosing the static array overload over the dynamic one is just plain wrong.
This is an intended behavior. An array literal has dynamic array type *by default*. But all of literals in D behave as polymorphic. char c = 'A'; // character literal has char type by default dchar d = 'A'; // but it may be implicitly typed as wchar/dchar string str = "hello"; dstring dstr = "hello"; // string literal is implicitly typed as dstring int[] darr = [1,2,3]; int[3] darr = [1,2,3]; // implicitly typed as int[3] So, an array literal [1,2,3] is implicitly convertible both to int[] and int[3]. And, int[3] is more specialized than int[], so overload resolution will choose the first 'bar'. Kenji Hara
Dec 09 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 08:29:02 Kenji Hara wrote:
 On Tuesday, 10 December 2013 at 07:15:43 UTC, Jonathan M Davis
 
 wrote:
 On Monday, December 09, 2013 22:59:49 Ali Çehreli wrote:
 On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array
 types.
 
 Let's suppose we have these overloaded functions:
 
 import std.stdio;
 
 void bar(const(int[3]) arr)
 {
 
       writeln("static array");
 
 }
 
 void bar(const(int[]) arr)
 {
 
       writeln("array slice");
 
 }
 
 // In main we have something like that:
 int main(string[] args)
 {
 
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
 
 }
 
 Weird thing is that the static array version of bar is
 called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
The original question is valid then: [1,2,3] goes to the static array overload.
Then AFAIK, that's a bug. The type of array literals is always a dynamic array, so they should match dynamic array overloads rather than static array overloads, or if they match both due to an implicit conversion, there should be an ambiguity error. Choosing the static array overload over the dynamic one is just plain wrong.
This is an intended behavior. An array literal has dynamic array type *by default*. But all of literals in D behave as polymorphic. char c = 'A'; // character literal has char type by default dchar d = 'A'; // but it may be implicitly typed as wchar/dchar string str = "hello"; dstring dstr = "hello"; // string literal is implicitly typed as dstring int[] darr = [1,2,3]; int[3] darr = [1,2,3]; // implicitly typed as int[3] So, an array literal [1,2,3] is implicitly convertible both to int[] and int[3]. And, int[3] is more specialized than int[], so overload resolution will choose the first 'bar'.
I'd argue that it would be far better to give an ambiguity error rather than silently pick one over the other. In general, having a literal of any kind pick a particular overload when it can match multiple is just begging for trouble. - Jonathan M Davis
Dec 09 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 07:46:25 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 10, 2013 08:29:02 Kenji Hara wrote:
 On Tuesday, 10 December 2013 at 07:15:43 UTC, Jonathan M Davis
 
 wrote:
 On Monday, December 09, 2013 22:59:49 Ali Çehreli wrote:
 On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array
 types.
 
 Let's suppose we have these overloaded functions:
 
 import std.stdio;
 
 void bar(const(int[3]) arr)
 {
 
       writeln("static array");
 
 }
 
 void bar(const(int[]) arr)
 {
 
       writeln("array slice");
 
 }
 
 // In main we have something like that:
 int main(string[] args)
 {
 
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
 
 }
 
 Weird thing is that the static array version of bar is
 called,
 but typeof().stringof is int[], not int[3].
Array literals are always dynamic arrays. int[3] is a static array. - Jonathan M Davis
The original question is valid then: [1,2,3] goes to the static array overload.
Then AFAIK, that's a bug. The type of array literals is always a dynamic array, so they should match dynamic array overloads rather than static array overloads, or if they match both due to an implicit conversion, there should be an ambiguity error. Choosing the static array overload over the dynamic one is just plain wrong.
This is an intended behavior. An array literal has dynamic array type *by default*. But all of literals in D behave as polymorphic. char c = 'A'; // character literal has char type by default dchar d = 'A'; // but it may be implicitly typed as wchar/dchar string str = "hello"; dstring dstr = "hello"; // string literal is implicitly typed as dstring int[] darr = [1,2,3]; int[3] darr = [1,2,3]; // implicitly typed as int[3] So, an array literal [1,2,3] is implicitly convertible both to int[] and int[3]. And, int[3] is more specialized than int[], so overload resolution will choose the first 'bar'.
I'd argue that it would be far better to give an ambiguity error rather than silently pick one over the other. In general, having a literal of any kind pick a particular overload when it can match multiple is just begging for trouble. - Jonathan M Davis´
I use this implict converting to static arrays very often and if we deprecate it, we really need something to declare static array literals. Since [1, 2, 3] is always dynamic we need something like C's {1, 2, 3} (But that would maybe conflict with struct literals). Kenji But eben if [1, 2, 3] is implicit converted to int[3], it is still allocated on the heap, right?
Dec 10 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 09:00:22 Namespace wrote:
 I use this implict converting to static arrays very often and if
 we deprecate it, we really need something to declare static array
 literals.
Implicit conversion isn't the problem. It's the fact that there are two possible matches, and it picks one over the other rather than requiring the programmer to indicate which one is correct (e.g. via casting). That's just going to lead to bugs. If there is no conflict, then the implicit conversion is fine. It's just that when there is a conflict that it's a problem. We have similar problems with stuff like void foo(bool b) {...} void foo(long l) {...} foo(1); //calls the bool overload There was a huge thread on this a while back where almost no one other than Walter thought that this behavior was good, and it was clearly causing bugs (Walter argued that the solution was to just add an overload for int rather than fixing the conversion problem). IMHO, there should be no implicit conversion of literals when there's a conflict. It should result in an ambiguity error so that the programmer has the opportunity to indicate the correct overload. - Jonathan M Davis
Dec 10 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 08:26:34 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 10, 2013 09:00:22 Namespace wrote:
 I use this implict converting to static arrays very often and 
 if
 we deprecate it, we really need something to declare static 
 array
 literals.
Implicit conversion isn't the problem. It's the fact that there are two possible matches, and it picks one over the other rather than requiring the programmer to indicate which one is correct (e.g. via casting). That's just going to lead to bugs. If there is no conflict, then the implicit conversion is fine. It's just that when there is a conflict that it's a problem.
Ok.
 We have similar problems with stuff like

 void foo(bool b) {...}
 void foo(long l) {...}

 foo(1); //calls the bool overload

 There was a huge thread on this a while back where almost no 
 one other than
 Walter thought that this behavior was good, and it was clearly 
 causing bugs
 (Walter argued that the solution was to just add an overload 
 for int rather
 than fixing the conversion problem). IMHO, there should be no 
 implicit
 conversion of literals when there's a conflict. It should 
 result in an
 ambiguity error so that the programmer has the opportunity to 
 indicate the
 correct overload.

 - Jonathan M Davis
Yeah I remember, but Kenji made a Pull Request to change this. Regardless it would be very useful to have static array literals.
Dec 10 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 Yeah I remember, but Kenji made a Pull Request to change this.
 Regardless it would be very useful to have static array literals.
It should be possible to do that via a templated function which takes a static array and then returns it. e.g. auto staticLiteral(T, size_t n)(T[n] literal) { return literal; } auto staticArray = staticLiteral([1, 2, 3, 4]); The compiler should optimize out the heap allocation, since the literal is directly converted to a static array (it might not optimize it now, but it definitely should, in which case, you're effectively creating a static array literal without any heap allocations). Maybe that's more verbose than would be ideal, but it allows us to essentially have static array literals without having to add anything to the language. - Jonathan M Davis
Dec 10 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 09:28:27 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 Yeah I remember, but Kenji made a Pull Request to change this.
 Regardless it would be very useful to have static array 
 literals.
It should be possible to do that via a templated function which takes a static array and then returns it. e.g. auto staticLiteral(T, size_t n)(T[n] literal) { return literal; } auto staticArray = staticLiteral([1, 2, 3, 4]); The compiler should optimize out the heap allocation, since the literal is directly converted to a static array (it might not optimize it now, but it definitely should, in which case, you're effectively creating a static array literal without any heap allocations). Maybe that's more verbose than would be ideal, but it allows us to essentially have static array literals without having to add anything to the language. - Jonathan M Davis
Ugly. Why not {1, 2, 3} or [1, 2, 3]s. The compiler could (as long as necessary) rewrite this to your ugly solution. But library solutions are always ugly and mostly bad and bug prone. See scoped, Typedef and destroy.
Dec 10 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 10:33:33 Namespace wrote:
 On Tuesday, 10 December 2013 at 09:28:27 UTC, Jonathan M Davis
 
 wrote:
 On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 Yeah I remember, but Kenji made a Pull Request to change this.
 Regardless it would be very useful to have static array
 literals.
It should be possible to do that via a templated function which takes a static array and then returns it. e.g. auto staticLiteral(T, size_t n)(T[n] literal) { return literal; } auto staticArray = staticLiteral([1, 2, 3, 4]); The compiler should optimize out the heap allocation, since the literal is directly converted to a static array (it might not optimize it now, but it definitely should, in which case, you're effectively creating a static array literal without any heap allocations). Maybe that's more verbose than would be ideal, but it allows us to essentially have static array literals without having to add anything to the language. - Jonathan M Davis
Ugly. Why not {1, 2, 3} or [1, 2, 3]s. The compiler could (as long as necessary) rewrite this to your ugly solution. But library solutions are always ugly and mostly bad and bug prone. See scoped, Typedef and destroy.
Walter and Andrei are very much against adding anything further to the language when it can be done in a library instead. {1, 2, 3} conflicts with C- style struct construction, and while [1, 2, 3]s is nice and short, all it does over staticLiteral([1, 2, 3]) is save some typing, and it requires language changes, whereas it's trivial in comparison to do something like this in a library. In fact, if we were to start over with D now, there would be a number of things that would just be in the library instead of the language (e.g. Andrei has stated several times that new should not have been a keyword and that it should have been handled by the standard library instead of the language). But it's too late for that now, so pretty much all of the stuff that might not end up the language if we were to start over is going to stay. However, that doesn't mean that we're going to be anything more like that in the language when we can do it in the library. - Jonathan M Davis
Dec 10 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 09:42:50 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 10, 2013 10:33:33 Namespace wrote:
 On Tuesday, 10 December 2013 at 09:28:27 UTC, Jonathan M Davis
 
 wrote:
 On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 Yeah I remember, but Kenji made a Pull Request to change 
 this.
 Regardless it would be very useful to have static array
 literals.
It should be possible to do that via a templated function which takes a static array and then returns it. e.g. auto staticLiteral(T, size_t n)(T[n] literal) { return literal; } auto staticArray = staticLiteral([1, 2, 3, 4]); The compiler should optimize out the heap allocation, since the literal is directly converted to a static array (it might not optimize it now, but it definitely should, in which case, you're effectively creating a static array literal without any heap allocations). Maybe that's more verbose than would be ideal, but it allows us to essentially have static array literals without having to add anything to the language. - Jonathan M Davis
Ugly. Why not {1, 2, 3} or [1, 2, 3]s. The compiler could (as long as necessary) rewrite this to your ugly solution. But library solutions are always ugly and mostly bad and bug prone. See scoped, Typedef and destroy.
Walter and Andrei are very much against adding anything further to the language when it can be done in a library instead. {1, 2, 3} conflicts with C- style struct construction, and while [1, 2, 3]s is nice and short, all it does over staticLiteral([1, 2, 3]) is save some typing, and it requires language changes, whereas it's trivial in comparison to do something like this in a library. In fact, if we were to start over with D now, there would be a number of things that would just be in the library instead of the language (e.g. Andrei has stated several times that new should not have been a keyword and that it should have been handled by the standard library instead of the language). But it's too late for that now, so pretty much all of the stuff that might not end up the language if we were to start over is going to stay. However, that doesn't mean that we're going to be anything more like that in the language when we can do it in the library. - Jonathan M Davis
scoped waste a lot of space, Typedef is mostly unuseable and destroy is buggy with alias this and doesn't free the space (of course this is intended). I would prefer to do nothing, than a library solution. But let's wait and see. :)
Dec 10 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 and while [1, 2, 3]s is nice and  short, all it does
 over staticLiteral([1, 2, 3]) is save some typing, and it 
 requires language changes,
[1, 2, 3]s seems nice.
Dec 10 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 12:54:58 UTC, bearophile wrote:
 Jonathan M Davis:

 and while [1, 2, 3]s is nice and  short, all it does
 over staticLiteral([1, 2, 3]) is save some typing, and it 
 requires language changes,
[1, 2, 3]s seems nice.
What's with {1, 2, 3}? Should be easy to implement and it's known
Dec 10 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 What's with {1, 2, 3}? Should be easy to implement and it's 

In D {} has plenty of meanings already :-) Bye, bearophile
Dec 10 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 14:20:51 UTC, bearophile wrote:
 Namespace:

 What's with {1, 2, 3}? Should be easy to implement and it's 

In D {} has plenty of meanings already :-) Bye, bearophile
That is no reason against it. ;)
Dec 10 2013
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 14:20:51 UTC, bearophile wrote:
 Namespace:

 What's with {1, 2, 3}? Should be easy to implement and it's 

In D {} has plenty of meanings already :-) Bye, bearophile
I've tried it in the last hour and as I thought, with a few changes it is very easy to implement (it needs currently ~30 lines - however my knowledge of the compiler is very limited, so that it could need some more changes). But a short test shows, that something like this is possible with my changes: ---- int[] arr0 = [1, 2, 3]; assert(is(typeof(arr0) == int[])); assert(arr0 == [1, 2, 3]); int[3] arr1 = {1, 2, 3}; assert(is(typeof(arr1) == int[3])); assert(arr1 == [1, 2, 3]); int[] arr2 = {4, 5, 6}; assert(is(typeof(arr2) == int[3])); assert(arr2 == [4, 5, 6]); ---- I like it. :D
Dec 10 2013
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 10 December 2013 at 14:20:51 UTC, bearophile wrote:
 Namespace:

 What's with {1, 2, 3}? Should be easy to implement and it's 

In D {} has plenty of meanings already :-) Bye, bearophile
You was right, it was terrible and so I tried [1, 2, 3]s as syntax. It has cost me hours but now this works pretty well: ---- import std.stdio; void foo(int[3] arr) { assert(is(typeof(arr) == int[3])); } void bar(T)(T arr) { assert(is(T == int[3])); } void main() { int[] arr0 = [1, 2, 3]; assert(is(typeof(arr0) == int[])); assert(arr0 == [1, 2, 3]); int[3] arr1 = [4, 5, 6]s; assert(is(typeof(arr1) == int[3])); assert(arr1 == [4, 5, 6]); int[] arr2 = [7, 8, 9]s; assert(is(typeof(arr2) == int[3])); assert(arr2 == [7, 8, 9]); foo([1, 2, 3]); foo([4, 5, 6]s); bar([44, 55, 66]s); auto arr3 = [111, 222, 333]; assert(is(typeof(arr3) == int[])); auto arr4 = [444, 555, 666]s; assert(is(typeof(arr4) == int[3])); } ----
Dec 10 2013
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 00:37:24 UTC, Namespace wrote:
 On Tuesday, 10 December 2013 at 14:20:51 UTC, bearophile wrote:
 Namespace:

 What's with {1, 2, 3}? Should be easy to implement and it's 

In D {} has plenty of meanings already :-) Bye, bearophile
You was right, it was terrible and so I tried [1, 2, 3]s as syntax. It has cost me hours but now this works pretty well: ---- import std.stdio; void foo(int[3] arr) { assert(is(typeof(arr) == int[3])); } void bar(T)(T arr) { assert(is(T == int[3])); } void main() { int[] arr0 = [1, 2, 3]; assert(is(typeof(arr0) == int[])); assert(arr0 == [1, 2, 3]); int[3] arr1 = [4, 5, 6]s; assert(is(typeof(arr1) == int[3])); assert(arr1 == [4, 5, 6]); int[] arr2 = [7, 8, 9]s; assert(is(typeof(arr2) == int[3])); assert(arr2 == [7, 8, 9]); foo([1, 2, 3]); foo([4, 5, 6]s); bar([44, 55, 66]s); auto arr3 = [111, 222, 333]; assert(is(typeof(arr3) == int[])); auto arr4 = [444, 555, 666]s; assert(is(typeof(arr4) == int[3])); } ----
Would be nice if someone could review it, maybe it's worth to add: Branch: https://github.com/Dgame/dmd/tree/static_array_literals Commit: https://github.com/Dgame/dmd/commit/6296057d919d50b407d4533bab5d2a21fba6230c
Dec 10 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/10/2013 04:37 PM, Namespace wrote:

      int[] arr2 = [7, 8, 9]s;
      assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array? Ali
Dec 10 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 04:01:11 UTC, Ali Çehreli wrote:
 On 12/10/2013 04:37 PM, Namespace wrote:

      int[] arr2 = [7, 8, 9]s;
      assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array? Ali
That is intended (but can be discussed of course). It was often desired to write int[$] arr = [1, 2, 3]; to auto-determine the dimension. And my change does something like that: if you assign a static array to a slice, the dimension is auto-determined and the type is adapted.
Dec 11 2013
parent reply "Chris Cain" <clcain uncg.edu> writes:
On Wednesday, 11 December 2013 at 09:49:13 UTC, Namespace wrote:
 On Wednesday, 11 December 2013 at 04:01:11 UTC, Ali Çehreli 
 wrote:
 On 12/10/2013 04:37 PM, Namespace wrote:

     int[] arr2 = [7, 8, 9]s;
     assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array? Ali
That is intended (but can be discussed of course). It was often desired to write int[$] arr = [1, 2, 3]; to auto-determine the dimension. And my change does something like that: if you assign a static array to a slice, the dimension is auto-determined and the type is adapted.
I agree with Ali. arr2 says it's a dynamic array but it's not. This could easily lead to errors worse than the class caused by implicit conversions (what's worse than explicitly saying you want an x but getting a y instead?). `int[$]` for this purpose would be acceptable, however. I actually like that idea, personally.
Dec 11 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 16:28:39 UTC, Chris Cain wrote:
 On Wednesday, 11 December 2013 at 09:49:13 UTC, Namespace wrote:
 On Wednesday, 11 December 2013 at 04:01:11 UTC, Ali Çehreli 
 wrote:
 On 12/10/2013 04:37 PM, Namespace wrote:

    int[] arr2 = [7, 8, 9]s;
    assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array? Ali
That is intended (but can be discussed of course). It was often desired to write int[$] arr = [1, 2, 3]; to auto-determine the dimension. And my change does something like that: if you assign a static array to a slice, the dimension is auto-determined and the type is adapted.
I agree with Ali. arr2 says it's a dynamic array but it's not. This could easily lead to errors worse than the class caused by implicit conversions (what's worse than explicitly saying you want an x but getting a y instead?). `int[$]` for this purpose would be acceptable, however. I actually like that idea, personally.
Ok, I will change that. ;) And I will try to implement the syntax for int[$].
Dec 11 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 18:31:20 UTC, Namespace wrote:
 On Wednesday, 11 December 2013 at 16:28:39 UTC, Chris Cain 
 wrote:
 On Wednesday, 11 December 2013 at 09:49:13 UTC, Namespace 
 wrote:
 On Wednesday, 11 December 2013 at 04:01:11 UTC, Ali Çehreli 
 wrote:
 On 12/10/2013 04:37 PM, Namespace wrote:

   int[] arr2 = [7, 8, 9]s;
   assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array? Ali
That is intended (but can be discussed of course). It was often desired to write int[$] arr = [1, 2, 3]; to auto-determine the dimension. And my change does something like that: if you assign a static array to a slice, the dimension is auto-determined and the type is adapted.
I agree with Ali. arr2 says it's a dynamic array but it's not. This could easily lead to errors worse than the class caused by implicit conversions (what's worse than explicitly saying you want an x but getting a y instead?). `int[$]` for this purpose would be acceptable, however. I actually like that idea, personally.
Ok, I will change that. ;) And I will try to implement the syntax for int[$].
Was a bit tricky but it works now (even if it may not be perfect): https://github.com/Dgame/dmd/commits/static_array_literals Example: ---- import std.stdio; void foo(int[3] arr) { assert(is(typeof(arr) == int[3])); } void bar(T)(T arr) { assert(is(T == int[3])); } void quatz(int[] arr) { assert(is(typeof(arr) == int[])); } void main() { int[] arr0 = [1, 2, 3]; assert(is(typeof(arr0) == int[])); assert(arr0 == [1, 2, 3]); int[3] arr1 = [4, 5, 6]s; assert(is(typeof(arr1) == int[3])); assert(arr1 == [4, 5, 6]); int[] arr2 = [7, 8, 9]s; assert(is(typeof(arr2) == int[/*3*/])); assert(arr2 == [7, 8, 9]); int[$] arr_a1 = [54, 74, 90, 2010]; assert(is(typeof(arr_a1) == int[4])); assert(arr_a1 == [54, 74, 90, 2010]); int[$] arr_a2 = [2010, 90, 74, 54]s; assert(is(typeof(arr_a2) == int[4])); assert(arr_a2 == [2010, 90, 74, 54]); foo([1, 2, 3]); foo([4, 5, 6]s); bar([44, 55, 66]s); auto arr3 = [111, 222, 333]; assert(is(typeof(arr3) == int[])); auto arr4 = [444, 555, 666]s; assert(is(typeof(arr4) == int[3])); quatz([3, 2, 1]); quatz([8, 7, 6]s); } ----
Dec 11 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 void main() {
 	int[] arr0 = [1, 2, 3];
 	assert(is(typeof(arr0) == int[]));
 	assert(arr0 == [1, 2, 3]);

 	int[3] arr1 = [4, 5, 6]s;
 	assert(is(typeof(arr1) == int[3]));
 	assert(arr1 == [4, 5, 6]);

 	int[] arr2 = [7, 8, 9]s;
 	assert(is(typeof(arr2) == int[/*3*/]));
 	assert(arr2 == [7, 8, 9]);

 	int[$] arr_a1 = [54, 74, 90, 2010];
 	assert(is(typeof(arr_a1) == int[4]));
 	assert(arr_a1 == [54, 74, 90, 2010]);

 	int[$] arr_a2 = [2010, 90, 74, 54]s;
 	assert(is(typeof(arr_a2) == int[4]));
 	assert(arr_a2 == [2010, 90, 74, 54]);

 	foo([1, 2, 3]);
 	foo([4, 5, 6]s);

 	bar([44, 55, 66]s);

 	auto arr3 = [111, 222, 333];
 	assert(is(typeof(arr3) == int[]));

 	auto arr4 = [444, 555, 666]s;
 	assert(is(typeof(arr4) == int[3]));

 	quatz([3, 2, 1]);
 	quatz([8, 7, 6]s);
 }
Very good, this seems a step forward for D. Are you going to create two pull requests for dmd? (it will not be accepted before dmd 2.066). Is it also guarding against this? http://d.puremagic.com/issues/show_bug.cgi?id=3849 That in short is this mistake (this currently doesn't give errors): string[3] a = ["red""green","blue"]; void main() {} Bye, bearophile
Dec 11 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 19:51:24 UTC, bearophile wrote:
 Namespace:

 void main() {
 	int[] arr0 = [1, 2, 3];
 	assert(is(typeof(arr0) == int[]));
 	assert(arr0 == [1, 2, 3]);

 	int[3] arr1 = [4, 5, 6]s;
 	assert(is(typeof(arr1) == int[3]));
 	assert(arr1 == [4, 5, 6]);

 	int[] arr2 = [7, 8, 9]s;
 	assert(is(typeof(arr2) == int[/*3*/]));
 	assert(arr2 == [7, 8, 9]);

 	int[$] arr_a1 = [54, 74, 90, 2010];
 	assert(is(typeof(arr_a1) == int[4]));
 	assert(arr_a1 == [54, 74, 90, 2010]);

 	int[$] arr_a2 = [2010, 90, 74, 54]s;
 	assert(is(typeof(arr_a2) == int[4]));
 	assert(arr_a2 == [2010, 90, 74, 54]);

 	foo([1, 2, 3]);
 	foo([4, 5, 6]s);

 	bar([44, 55, 66]s);

 	auto arr3 = [111, 222, 333];
 	assert(is(typeof(arr3) == int[]));

 	auto arr4 = [444, 555, 666]s;
 	assert(is(typeof(arr4) == int[3]));

 	quatz([3, 2, 1]);
 	quatz([8, 7, 6]s);
 }
Very good, this seems a step forward for D. Are you going to create two pull requests for dmd? (it will not be accepted before dmd 2.066).
I'm unsure. I'm not that familiar with dmd at all, so maybe some more advanced guy like Kenji should review my code and create an own, better pull. What do you mean?
 Is it also guarding against this?
 http://d.puremagic.com/issues/show_bug.cgi?id=3849

 That in short is this mistake (this currently doesn't give 
 errors):

 string[3] a = ["red""green","blue"];
 void main() {}

 Bye,
 bearophile
Not yet tested, but I will. :)
Dec 11 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 I'm unsure. I'm not that familiar with dmd at all, so maybe 
 some more advanced guy like Kenji should review my code and 
 create an own, better pull.
In that code there is both the [$] and the []s syntaxes. So it's better to submit them as two separated pull requests for the D front-end. Lately Kenji seems a little less active, but he will probably be glad to review your code, fix it, etc.
 What do you mean?
Walter said that dmd 2.065 is meant only as bug-fix release (expecially ICEs) so no "significant" language enhancement requests will be added in dmd 2.065, and they have to wait for dmd 2.066. But dmd 2.065 is supposed to end quicker, so we will not wait a lot of time.
 Not yet tested, but I will. :)
(Issue 3849 also suggests the "..." syntax inside array literals to fulfill a narrow corner case that Walter seems to appreciate. I think it's not an important syntax.) Bye, bearophile
Dec 11 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 20:50:01 UTC, bearophile wrote:
 Namespace:

 I'm unsure. I'm not that familiar with dmd at all, so maybe 
 some more advanced guy like Kenji should review my code and 
 create an own, better pull.
In that code there is both the [$] and the []s syntaxes. So it's better to submit them as two separated pull requests for the D front-end. Lately Kenji seems a little less active, but he will probably be glad to review your code, fix it, etc.
 What do you mean?
Walter said that dmd 2.065 is meant only as bug-fix release (expecially ICEs) so no "significant" language enhancement requests will be added in dmd 2.065, and they have to wait for dmd 2.066. But dmd 2.065 is supposed to end quicker, so we will not wait a lot of time.
 Not yet tested, but I will. :)
(Issue 3849 also suggests the "..." syntax inside array literals to fulfill a narrow corner case that Walter seems to appreciate. I think it's not an important syntax.) Bye, bearophile
I'm pretty nervous, but here is the first: https://github.com/D-Programming-Language/dmd/pull/2952
Dec 11 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 I'm pretty nervous, but here is the first: 
 https://github.com/D-Programming-Language/dmd/pull/2952
Good. Keep in mind that at best it will take a month or more for your patch to be accepted. Also patches that implement basic language features like this pass a stringent process of review, that can be laborious and a bit painful. And even after after all that work there's a certain probability of rejection. So you have to build stamina and accumulate patience :-) (Other kind of patches, like D front-end bug fixes or Phobos improvements are faster and often much less painful). Bye, bearophile
Dec 11 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 11 December 2013 at 23:20:30 UTC, bearophile wrote:
 Namespace:

 I'm pretty nervous, but here is the first: 
 https://github.com/D-Programming-Language/dmd/pull/2952
Good. Keep in mind that at best it will take a month or more for your patch to be accepted. Also patches that implement basic language features like this pass a stringent process of review, that can be laborious and a bit painful. And even after after all that work there's a certain probability of rejection. So you have to build stamina and accumulate patience :-) (Other kind of patches, like D front-end bug fixes or Phobos improvements are faster and often much less painful). Bye, bearophile
Your gig: https://github.com/D-Programming-Language/dmd/pull/2952#discussion_r8288045
Dec 11 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Your gig: 
 https://github.com/D-Programming-Language/dmd/pull/2952#discussion_r8288045
My enhancement request was for the array[$] syntax. The idea of []s was invented by someone else (Timothee Cour?). I like the practical comments by Hara. If Kenji thinks the []s is not useful for efficiency (because the efficiency can be obtained with just improvements of the compiler), then the []s syntax becomes less necessary. On the other hand this is an interesting use case that compiler improvements alone could not be enough to allow: void fun(int[3]) {} void main() { int[3] x = [1, 2, 3]; fun(x); // OK fun([1, 2, 3]); // error fun([1, 2, 3]s); // OK } Are vector ops supported? int[6] a; a = [1,2,3]s[] + [4,5,6]s[]; DIP34 is still a draft, and it shows, some corner cases are missing in that document and need to be found, fleshed out and added to the DIP34. Bye, bearophile
Dec 11 2013
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
On Wed, Dec 11, 2013 at 5:17 PM, bearophile <bearophileHUGS lycos.com>wrote:

 Namespace:

  Your gig: https://github.com/D-Programming-Language/dmd/pull/
 2952#discussion_r8288045
My enhancement request was for the array[$] syntax. The idea of []s was invented by someone else (Timothee Cour?). I like the practical comments by Hara. If Kenji thinks the []s is not useful for efficiency (because the efficiency can be obtained with just improvements of the compiler), then the []s syntax becomes less necessary. On the other hand this is an interesting use case that compiler improvements alone could not be enough to allow: void fun(int[3]) {} void main() { int[3] x = [1, 2, 3]; fun(x); // OK fun([1, 2, 3]); // error fun([1, 2, 3]s); // OK }
yes, that was the prime motivation for DIP34, being able to pass un-ambiguously a static array to a function without having to declare an intermediate variable first. when fun() has overloads for both static and non-static arrays (or is just declared as fun(T)(T a) ), the compiler cannot guess whether fun([1,2,3]) asks for static or dynamic array, and probably has to assume dynamic array. And int[$] would require declaring a variable before passing it, eg: int[$]x=[1,2,3]. With [1,2,3]s, there is no ambiguity.
 Are vector ops supported?

 int[6] a;
 a = [1,2,3]s[] + [4,5,6]s[];

 DIP34 is still a draft, and it shows, some corner cases are missing in
 that document and need to be found, fleshed out and added to the DIP34.

 Bye,
 bearophile
Dec 11 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Timothee Cour:

 void fun(int[3]) {}
 void main() {
     int[3] x = [1, 2, 3];
     fun(x); // OK
     fun([1, 2, 3]); // error
     fun([1, 2, 3]s); // OK
 }
Sorry, there's no error there.
 yes, that was the prime motivation for DIP34,
It seems Hara has received your message: https://d.puremagic.com/issues/show_bug.cgi?id=8903#c7 Bye, bearophile
Dec 11 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Your gig: 
 https://github.com/D-Programming-Language/dmd/pull/2952#discussion_r8288045
This is part of the thread there:
 Furhtermore, what if we indeed want to pass a dynamic array ?<<
Kenji> Use cast. In real world, if overloaded function takes both int[] and int[3], normally int[3] version would provide specialized implementation for 3 length arrays (eg. unroll the loop to operate each elements of the given array). Therefore force to invoke int[] version with array literal is not usual situation. Cast will fit in such case.< If I have a function foo that takes a slice as input, and I want to pass it two arrays, the first time allocated on the heap and the second on the stack, I have to use an auxiliary variable: void foo(int[]) {} void main() { foo([1, 2, 3]); int[3] tmp = [4, 5, 6]; foo(tmp); } DMD generates: __Dmain comdat L0: push EBX mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ push 3 push EAX call near ptr __d_arrayliteralTX mov EBX,EAX mov dword ptr [EAX],1 xor EAX,EAX mov dword ptr 4[EBX],2 mov dword ptr 8[EBX],3 add ESP,8 pop EBX ret With the []s syntax it should become: void foo(int[]) {} void main() { foo([1, 2, 3]); foo([4, 5, 6]s); } But I don't know how much common is such need. In the Rust language when you write an array literal you always prefix it with a symbol, to tell the compiler where you want to allocate it. So I think it's not so useless :-) Bye, bearophile
Dec 12 2013
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
Why don't you discuss on github?

And finally I did it:

----
auto[$] a_arr2 = dyn_arr[4 .. 8];
assert(is(typeof(a_arr2) == int[4]));
----

I will make a Pull Request tomorrow. Hope my code isn't that bad. 
:/
Dec 12 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Why don't you discuss on github?
I sometimes discuss on GitHub, but when the amount of things I have to say are large enough I think a forum like this is better. Also I don't like the lack of threading in GitHub comments.
 And finally I did it:

 ----
 auto[$] a_arr2 = dyn_arr[4 .. 8];
 assert(is(typeof(a_arr2) == int[4]));
 ----

 I will make a Pull Request tomorrow.
Good :-) ------------------ Regarding fixed sized arrays there's another point, visible here: void main() { int[3] a, b, c; pragma(msg, typeof(a[] + b[])); } It prints: int[] So it seems the compiler loses track of the compile-time knowledge of the length of those arrays (it's probably caused by the slicing). In my opinion this is quite important because such loss of information makes it harder for the compiler to rewrite code as "c[] = a[] + b[]" as: foreach (immutable i; 0 .. 3) c[i] = a[i] + b[i]; That later the back-end should unroll in just three sums (this is routinely done by the Fortran array ops); and a smart back-end can even rewrite with a single SIMD instruction (adding padding to the a, b, and c arrays making them 4 integers long). Bye, bearophile
Dec 12 2013
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 13 December 2013 at 00:37:36 UTC, Namespace wrote:
 Why don't you discuss on github?

 And finally I did it:

 ----
 auto[$] a_arr2 = dyn_arr[4 .. 8];
 assert(is(typeof(a_arr2) == int[4]));
 ----

 I will make a Pull Request tomorrow. Hope my code isn't that 
 bad. :/
Done: https://github.com/D-Programming-Language/dmd/pull/2958
Dec 13 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Done:
 https://github.com/D-Programming-Language/dmd/pull/2958
If you have a situation like this: int[3] foo() { typeof(return) a; return a; } void main() { int[100] b; b[0 .. 3] = foo(); } Can you use code like this to infer the length of the part needed to copy? int[3] foo() { typeof(return) a; return a; } void main() { int[100] b; b[0 .. $] = foo(); } Bye, bearophile
Dec 17 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Tuesday, 17 December 2013 at 17:01:55 UTC, bearophile wrote:
 Namespace:

 Done:
 https://github.com/D-Programming-Language/dmd/pull/2958
If you have a situation like this: int[3] foo() { typeof(return) a; return a; } void main() { int[100] b; b[0 .. 3] = foo(); } Can you use code like this to infer the length of the part needed to copy? int[3] foo() { typeof(return) a; return a; } void main() { int[100] b; b[0 .. $] = foo(); } Bye, bearophile
No, not currently. But it is an interesting idea. Maybe I will implement this. And as far as I have enough time, I will also add test cases. Maybe on christmas. :)
Dec 17 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 No, not currently. But it is an interesting idea. Maybe I will 
 implement this.
A use case: https://d.puremagic.com/issues/show_bug.cgi?id=11757#c3 Visible in this line: key2[0 .. digestSize] = key.md5Of; But my suggested syntax is not that good, here $ has already a meaning, that is the whole length of b, So some different idea is needed here :-( b[0 .. $] = foo(); Otherwise you have to write code like: b[0 .. ReturnType!foo.length] = foo();
Dec 17 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/17/2013 07:21 PM, bearophile wrote:

 But my suggested syntax is not that good, here $ has already a meaning,
 that is the whole length of b, So some different idea is needed here :-(

 b[0 .. $] = foo();
Sorry, I can't resist... Golden rule of system programming language syntax: When in doubt, reach for static: b[0 .. $tatic] = foo(); Done! :p Ali
Dec 19 2013
prev sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Thursday, 12 December 2013 at 18:20:25 UTC, bearophile wrote:
 Namespace:

 Your gig: 
 https://github.com/D-Programming-Language/dmd/pull/2952#discussion_r8288045
This is part of the thread there:
 Furhtermore, what if we indeed want to pass a dynamic array 
 ?<<
Kenji> Use cast. In real world, if overloaded function takes both int[] and int[3], normally int[3] version would provide specialized implementation for 3 length arrays (eg. unroll the loop to operate each elements of the given array). Therefore force to invoke int[] version with array literal is not usual situation. Cast will fit in such case.< If I have a function foo that takes a slice as input, and I want to pass it two arrays, the first time allocated on the heap and the second on the stack, I have to use an auxiliary variable: void foo(int[]) {} void main() { foo([1, 2, 3]); int[3] tmp = [4, 5, 6]; foo(tmp); }
There's a known issue that the function foo takes the slice of stack allocated data. Today some peoples argue that it is unsafe operation and should be disallowed in safe code.
 With the []s syntax it should become:


 void foo(int[]) {}
 void main() {
     foo([1, 2, 3]);
     foo([4, 5, 6]s);
 }


 But I don't know how much common is such need.

 In the Rust language when you write an array literal you always 
 prefix it with a symbol, to tell the compiler where you want to 
 allocate it. So I think it's not so useless :-)

 Bye,
 bearophile
I'm afraid that allowing foo([4, 5, 6]s) would easily cause memory corruption. I don't want to hurt language future by the trivial syntactic sugar. Kenji Hara
Dec 12 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 13 December 2013 at 04:13:04 UTC, Kenji Hara wrote:
 On Thursday, 12 December 2013 at 18:20:25 UTC, bearophile wrote:
 If I have a function foo that takes a slice as input, and I 
 want to pass it two arrays, the first time allocated on the 
 heap and the second on the stack, I have to use an auxiliary 
 variable:


 void foo(int[]) {}
 void main() {
    foo([1, 2, 3]);
    int[3] tmp = [4, 5, 6];
    foo(tmp);
 }
There's a known issue that the function foo takes the slice of stack allocated data. Today some peoples argue that it is unsafe operation and should be disallowed in safe code. Kenji Hara
I think there is consensus that in safe code this should be blocked.
Dec 12 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, December 13, 2013 07:19:50 Maxim Fomin wrote:
 On Friday, 13 December 2013 at 04:13:04 UTC, Kenji Hara wrote:
 On Thursday, 12 December 2013 at 18:20:25 UTC, bearophile wrote:
 If I have a function foo that takes a slice as input, and I
 want to pass it two arrays, the first time allocated on the
 heap and the second on the stack, I have to use an auxiliary
 variable:
 
 
 void foo(int[]) {}
 void main() {
 
    foo([1, 2, 3]);
    int[3] tmp = [4, 5, 6];
    foo(tmp);
 
 }
There's a known issue that the function foo takes the slice of stack allocated data. Today some peoples argue that it is unsafe operation and should be disallowed in safe code. Kenji Hara
I think there is consensus that in safe code this should be blocked.
Slicing a static array is exactly the same as taking the address of a local variable, except that you then have a length in addition to the address. If that slice is assigned to anything which has a lifetime greater than that of the static array that was sliced, then the slice will be referring to invalid memory. That's clearly system, and I don't see how anyone could even argue otherwise. Yes, there is plenty of code which is currently considered safe by the compiler which will break once slicing a static array is considered system like it needs to be (especially because static arrays are unfortunately automatically sliced when they're passed to a function which takes a dynamic array - I really wish that that were'n the case), but that can't be avoided. So, yes, changing it so that slicing a static array is system will cause annoying code breakage, but I don't see any way around it without breaking what safe means and does. - Jonathan M Davis
Dec 12 2013
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
I created a separate branch for the syntax Type[$] and auto[$]:
https://github.com/Dgame/dmd/commit/438a519d28d1683086083e673b2630a64c269f5f

Example:

----
int[$] arr_a1 = [54, 74, 90, 2010];
assert(is(typeof(arr_a1) == int[4]));
assert(arr_a1 == [54, 74, 90, 2010]);

int[$] arr_a2 = [2010, 90, 74, 54];
assert(is(typeof(arr_a2) == int[4]));
assert(arr_a2 == [2010, 90, 74, 54]);

int[] dyn_arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
int[$] stat_arr = dyn_arr[3 .. 6];
assert(is(typeof(stat_arr) == int[3]));

auto[$] a_arr1 = [1, 2, 3];
assert(is(typeof(a_arr1) == int[3]));

auto[$] a_arr2 = dyn_arr[4 .. 8]; /// Sadly not possible for me

//int s = 2, e = 7;
//int[$] stat_arr2 = dyn_arr[s .. e]; /// fails

//int[$] stat_arr3 = dyn_arr[]; /// fails
----

Sadly I don't know how I could deduce the type of:
----
auto[$] a_arr2 = dyn_arr[4 .. 8]; /// Sadly not possible for me
----

I will try this again before I open a pull request. Maybe some of 
you know how to do this?
Dec 12 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:

 Sadly I don't know how I could deduce the type of:
 ----
 auto[$] a_arr2 = dyn_arr[4 .. 8]; /// Sadly not possible for me
It seems a valid use case. Bye, bearophile
Dec 12 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
I presume the situation with this code is not changed by your 
patches:

string[3] a = ["red""green","blue"];
void main() {}

Bye,
bearophile
Dec 12 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
 string[3] a = ["red""green","blue"];
 void main() {}
I suggested to support such incomplete literals only with this extra syntax: int[3] a = [1, 2, ...]; void main() {} Bye, bearophile
Dec 12 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

      int[] arr2 = [7, 8, 9]s;
      assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array?
No, the type of the literal is of a fixed-side array, but it gets assigned to a dynamic array, so it's a slice. I am not sure but I Think arr2 data is allocated on the stack. It looks a little confusing, but I think it contains a rule we can learn. Bye, bearophile
Dec 11 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/11/2013 05:09 PM, bearophile wrote:

 Ali Çehreli:

      int[] arr2 = [7, 8, 9]s;
      assert(is(typeof(arr2) == int[3]));
That looks very confusing. The left-hand side looks like a slice, which I can append elements to but its type is a static array?
No, the type of the literal is of a fixed-side array, but it gets assigned to a dynamic array, so it's a slice.
No problem there.
 I am not sure but I Think
 arr2 data is allocated on the stack.
Although important, I wasn't considering that point at all.
 It looks a little confusing, but I
 think it contains a rule we can learn.
But look at the assertion: the type of the *slice* arr2 is int[3]. :)
 Bye,
 bearophile
Ali
Dec 12 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 But look at the assertion: the type of the *slice* arr2 is 
 int[3]. :)
I didn't notice that. It looks strange... I don't understand it. Bye, bearophile
Dec 12 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 12 December 2013 at 15:35:52 UTC, bearophile wrote:
 Ali Çehreli:

 But look at the assertion: the type of the *slice* arr2 is 
 int[3]. :)
I didn't notice that. It looks strange... I don't understand it. Bye, bearophile
I already pointed out why it was that way AND that it's "fixed" now. ;)
Dec 12 2013
prev sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Tuesday, 10 December 2013 at 09:28:27 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 auto staticLiteral(T, size_t n)(T[n] literal)
 {
     return literal;
 }

 auto staticArray = staticLiteral([1, 2, 3, 4]);
Why do you think this is possible? If an array literal should match _only_ dynamic array types, it would never work. Because compiler will try to match array literal to static array T[n]. The feature which I have described is working here. Kenji Hara
Dec 10 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 10, 2013 11:19:45 Kenji Hara wrote:
 On Tuesday, 10 December 2013 at 09:28:27 UTC, Jonathan M Davis
 
 wrote:
 On Tuesday, December 10, 2013 10:10:22 Namespace wrote:
 auto staticLiteral(T, size_t n)(T[n] literal)
 {
 
     return literal;
 
 }
 
 auto staticArray = staticLiteral([1, 2, 3, 4]);
Why do you think this is possible? If an array literal should match _only_ dynamic array types, it would never work. Because compiler will try to match array literal to static array T[n]. The feature which I have described is working here.
It doesn't need to match only dynamic array types. The problem is when you have an overload. e.g. auto foo(T[] arr) {...} auto foo(T[3] arr) {...} foo([1, 2, 3]); Silently selecting one of the two is bug-prone - especially if it's the static one that gets selected, as in most cases, it would be the dynamic one which matches. Having dynamic array literals implicitly convert to static arrays when they're assigned to static arrays makes sense when there's no ambiguity. And in general, something like staticLiteral should be unnecessary when passing to a function, as the array literal would be treated as a dynamic array or a static array depending on the function's parameters, but it could be useful in cases where you want to be explicit about the type or when using auto. And it may not be worth adding a function such as staticLiteral, but I think that it's better than trying to add static array literals to the language, particularly since we're trying to avoid adding features to the language when they can be implemented in the standard library instead. - Jonathan M Davis
Dec 10 2013
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 10 Dec 2013 00:26:22 -0800
schrieb Jonathan M Davis <jmdavisProg gmx.com>:

 On Tuesday, December 10, 2013 09:00:22 Namespace wrote:
 I use this implict converting to static arrays very often and if
 we deprecate it, we really need something to declare static array
 literals.
Implicit conversion isn't the problem. It's the fact that there are two possible matches, and it picks one over the other rather than requiring the programmer to indicate which one is correct (e.g. via casting). That's just going to lead to bugs. If there is no conflict, then the implicit conversion is fine. It's just that when there is a conflict that it's a problem. We have similar problems with stuff like void foo(bool b) {...} void foo(long l) {...} foo(1); //calls the bool overload There was a huge thread on this a while back where almost no one other than Walter thought that this behavior was good, and it was clearly causing bugs (Walter argued that the solution was to just add an overload for int rather than fixing the conversion problem). IMHO, there should be no implicit conversion of literals when there's a conflict. It should result in an ambiguity error so that the programmer has the opportunity to indicate the correct overload. - Jonathan M Davis
In the case above, *if* there was an int overload would you argue for still requiring to use foo(cast(int)1) ? Since that is what would come out of it when cast(int[3])[1,2,3] is required. That would hurt the readability of I/O functions that are specialized for all integral types. EndianStream comes to mind. e.g.: stream.write(cast(int)1); Since cast is a blunt tool, I expect APIs to change away from overloads entirely and use writeInt, writeUbyte etc. instead. -- Marco
Dec 10 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 10 Dec 2013 08:29:02 +0100
schrieb "Kenji Hara" <k.hara.pg gmail.com>:

 This is an intended behavior. An array literal has dynamic array=20
 type *by default*.
 But all of literals in D behave as polymorphic.
=20
 char c =3D 'A';   // character literal has char type by default
 dchar d =3D 'A';  // but it may be implicitly typed as wchar/dchar
=20
 string str =3D "hello";
 dstring dstr =3D "hello";  // string literal is implicitly typed as=20
 dstring
=20
 int[] darr =3D [1,2,3];
 int[3] darr =3D [1,2,3];   // implicitly typed as int[3]
=20
 So, an array literal [1,2,3] is implicitly convertible both to=20
 int[] and int[3].
 And, int[3] is more specialized than int[], so overload=20
 resolution will choose the first 'bar'.
=20
 Kenji Hara
So this is how it works. I honestly wouldn't have come up with this. Your example for char makes it clear why this implicit type changing is in place. The OP still has a point though. If they are so polymorphic and "try to specialize" as necessary, then D's typeof(=E2=80=A6) must always be in a Schr=C3=B6dinger cat-like state and only decide on an actual result when it is clear from static code analysis that every use of it's argument in the program leads to the same concrete type. Taking the following example as a failing case for this analysis: int[] arr1 =3D [1,2,3]; int[3] arr2 =3D [1,2,3]; writeln(typeof([1,2,3]).stringof); It must lead to a compiler error informing the user that [1,2,3] is simultaneously int[] and int[3]. --=20 Marco
Dec 10 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/10/2013 08:29 AM, Kenji Hara wrote:
 This is an intended behavior. An array literal has dynamic array type
 *by default*.
 But all of literals in D behave as polymorphic.

 char c = 'A';   // character literal has char type by default
 dchar d = 'A';  // but it may be implicitly typed as wchar/dchar

 string str = "hello";
 dstring dstr = "hello";  // string literal is implicitly typed as dstring

 int[] darr = [1,2,3];
 int[3] darr = [1,2,3];   // implicitly typed as int[3]

 So, an array literal [1,2,3] is implicitly convertible both to int[] and
 int[3].
 And, int[3] is more specialized than int[], so overload resolution will
 choose the first 'bar'.

 Kenji Hara
Match with implicit conversion cannot be what is really happening as otherwise the following call would be ambiguous: int bar(int[3] arr){ return 1; } int bar(double[] arr){ return 2; } int bar(int[] arr){ return 3; } static assert(bar([1,2,3])==1);
Dec 10 2013
prev sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 10 December 2013 at 07:29:03 UTC, Kenji Hara wrote:
 This is an intended behavior. An array literal has dynamic 
 array type *by default*.
 But all of literals in D behave as polymorphic.
One of good examples why weakly typed literals suck.
Dec 10 2013
prev sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 09 Dec 2013 23:15:27 -0800
schrieb Jonathan M Davis <jmdavisProg gmx.com>:

 On Monday, December 09, 2013 22:59:49 Ali =C3=87ehreli wrote:
 On 12/09/2013 10:52 PM, Jonathan M Davis wrote:
 On Tuesday, December 10, 2013 07:47:38 FreeSlave wrote:
 I just found weird D behavior about inference of array types.
=20
 Let's suppose we have these overloaded functions:
=20
 import std.stdio;
=20
 void bar(const(int[3]) arr)
 {
=20
       writeln("static array");
=20
 }
=20
 void bar(const(int[]) arr)
 {
=20
       writeln("array slice");
=20
 }
=20
 // In main we have something like that:
 int main(string[] args)
 {
=20
       bar([1,2,3]);
       writeln(typeof([1,2,3]).stringof);
       return 0;
=20
 }
=20
 Weird thing is that the static array version of bar is called,
 but typeof().stringof is int[], not int[3].
=20 Array literals are always dynamic arrays. int[3] is a static array. =20 - Jonathan M Davis
=20 The original question is valid then: [1,2,3] goes to the static array overload.
=20 Then AFAIK, that's a bug. The type of array literals is always a dynamic=
=20
 array, so they should match dynamic array overloads rather than static ar=
ray=20
 overloads, or if they match both due to an implicit conversion, there sho=
uld=20
 be an ambiguity error. Choosing the static array overload over the dynami=
c one=20
 is just plain wrong.
=20
 - Jonathan M Davis
=20
[1,2,3] looks like a static array to me. And if overload resolution picked the most specialized function it seems natural to call the int[3] version. My reasoning being that static arrays can be implicitly converted to dynamic array, but the reverse is not true. So I think it would be better to have [1,2,3] be a static array and keep the current behavoir, no?) --=20 Marco
Dec 10 2013
parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Tuesday, 10 December 2013 at 07:32:08 UTC, Marco Leise wrote:
 [1,2,3] looks like a static array to me. And if overload
 resolution picked the most specialized function it seems
 natural to call the int[3] version.
 My reasoning being that static arrays can be implicitly
 converted to dynamic array, but the reverse is not true. So I
 think it would be better to have [1,2,3] be a static array and
 keep the current behavoir, no?)
In early D1 age, array literals and string literals had had static array types which corresponding to the literals' element count. However it had caused template code bloat. void foo(T)(T arg) { ... } foo("aaa"); // instantiate foo!(char[3]) foo("bbbb"); // instantiate foo!(char[4]) foo([1,2]); // instantiate foo!(int[2]) foo([1,2,3]); // instantiate foo!(int[3]) So their types were changed to dynamic array by default. Kenji Hara
Dec 10 2013
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 10 Dec 2013 11:56:40 +0100
schrieb "Kenji Hara" <k.hara.pg gmail.com>:

 On Tuesday, 10 December 2013 at 07:32:08 UTC, Marco Leise wrote:
 [1,2,3] looks like a static array to me. And if overload
 resolution picked the most specialized function it seems
 natural to call the int[3] version.
 My reasoning being that static arrays can be implicitly
 converted to dynamic array, but the reverse is not true. So I
 think it would be better to have [1,2,3] be a static array and
 keep the current behavoir, no?)
In early D1 age, array literals and string literals had had static array types which corresponding to the literals' element count. However it had caused template code bloat. void foo(T)(T arg) { ... } foo("aaa"); // instantiate foo!(char[3]) foo("bbbb"); // instantiate foo!(char[4]) foo([1,2]); // instantiate foo!(int[2]) foo([1,2,3]); // instantiate foo!(int[3]) So their types were changed to dynamic array by default. Kenji Hara
I understand that. The string case probably being the most heavy weight one that prompted the change. Damn, compilers are complicated. -- Marco
Dec 10 2013