Thread overview | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 10, 2013 Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
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]. |
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 Ç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 > [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?) -- Marco |
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kenji Hara | 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
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kenji Hara | 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 > 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 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(…) must always be in a Schrödinger 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 = [1,2,3]; int[3] arr2 = [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]. -- Marco |
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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?
|
December 10, 2013 Re: Type inference and overloaded functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | 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
|
Copyright © 1999-2021 by the D Language Foundation