Bug 481 – Fixed-length arrays with automatically computed length
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2006-11-04T23:49:05Z
Last change time
2019-07-13T11:34:54Z
Keywords
pull
Assigned to
Walter Bright
Creator
Bill Baxter
Comments
Comment #0 by wbaxter — 2006-11-04T23:49:05Z
There needs to be a way to tell the compiler to count up how many elements there are in a fixed length array. In C++ you use empty brackets, [], but in D this means "create a dynamic array". Sometimes you want a fixed-length array but it's a pain to count up the elements by hand. The main example is embedding binary data, like images, into the program as code.
A possible syntax would be to use the pre-existing '$' or 'length' indicators to specify that the length of the array should be the length of the initializer:
int arr[$] = [1,2,3,4]; // makes an int[4]
int arr[length] = [1,2,3,4]; // ditto
int[$] arr = [1,2,3,4]; // ditto
int[length] arr = [1,2,3,4]; // ditto
Another option would be to re-use the keyword auto.
int arr[auto] = [1,2,3,4]; // makes an int[4]
int[auto] arr = [1,2,3,4]; // ditto
Using 'auto' makes sense in that the length really is part of the type of a fixed-length array, so really what you're saying is "automatically deduce just this part of the type for me".
Using 'auto' would also be extend naturally to associative arrays when/if there are initializers for those. For example:
int[auto] str_to_num = [ "one":1, "two":2, "three":3 ];
This would specify that value type is int, but let the key type be automatically deduced from the initializer.
Comment #1 by andrei — 2010-11-26T11:36:34Z
This enhancement's importance is raised by the fact that array literals have dynamic length by default, so simply writing
auto a = [1,2,3,4];
won't make a of type int[4].
I think using "[$]" is the most sensible option. The special meaning of "length" inside array brackets needs to be eliminated anyway, and "[auto]" may confuse people into thinking it's an associative array.
Comment #2 by bearophile_hugs — 2010-11-26T12:24:55Z
I agree that this syntax is good:
int[$] arr = [1,2,3,4];
But it solves only half of the problem.
Currently this compiles:
int[4] a = [1, 2, 3];
void main() {}
While this generates:
object.Exception: lengths don't match for array copy
void main() {
int[4] a = [1, 2, 3];
}
They are two different situations. But they don't look different, the first just look like a special case.
To solve the second half of the problem someone has suggested this syntax that looks good enough:
int[4] a = [1, 2, 3, ...];
a[3] is filled with typeof(a[0]).init.
For more info see bug 3849
Comment #3 by bruno.do.medeiros+deebugz — 2010-12-03T05:28:18Z
(In reply to comment #1)
> This enhancement's importance is raised by the fact that array literals have
> dynamic length by default, so simply writing
>
> auto a = [1,2,3,4];
>
> won't make a of type int[4].
>
> I think using "[$]" is the most sensible option.
I don't quite get this argument. If you have a syntax such as "[$]" (I assume you are referring to Bill's example of "int[$] arr"), then obviously
auto a = [1,2,3,4];
still won't make a of type int[4]...
The only way to use auto (in it current form) to declare a static array would be to have a syntax for a static array literal. Or to have a template and/or function to create the static array value. Isn't this latter alternative preferable? A bit more verbose, but no language changes should be necessary.
Comment #4 by bearophile_hugs — 2010-12-11T00:35:09Z
(In reply to comment #3)
> I don't quite get this argument.
Originally array literals used to create fixed length arrays:
auto a = [1,2,3,4];
==> int[4]
Later D was changed so that line creates a dynamic array:
auto a = [1,2,3,4];
==> int[]
that's handy, but now if you have a long array literal and you want a fixed-sized array you have to count how many items it has. This is not handy, especially if later you want to add or remove items from the array literal (in the source code).
It's not handy also because if by mistake you write a bigger number, empty items are silently created (but only for global fixed-sized literals):
int[5] a = [1,2,3,4];
==> int[5]
So Bill and others have suggested a simple syntax that is easy enough to read, understand and remember:
int[$] a = [1,2,3,4];
==> int[4]
And to avoid bugs produced by wrong number of items a second syntax may be introduced, that makes it explicit that there are some auto initialized items:
int[6] a = [1,2,3,4,...];
==> int[6]
Comment #5 by bruno.do.medeiros+deebugz — 2010-12-14T04:27:54Z
(In reply to comment #4)
> (In reply to comment #3)
> > I don't quite get this argument.
>
> Originally array literals used to create fixed length arrays:
Yes, I understood the use case for this problem, and how the [$] syntax would solve the limitation in a way.
But then we're not looking for a syntax that would also allows us to use auto (as in "auto a = [1,2,3,4];"), is that what we're saying?
Comment #6 by bearophile_hugs — 2010-12-14T13:24:26Z
(In reply to comment #5)
> But then we're not looking for a syntax that would also allows us to use auto
> (as in "auto a = [1,2,3,4];"), is that what we're saying?
Now I think I understand what you mean. You mean something like:
auto[$] a = [1,2,3,4];
==> int[4]
So auto lets the D compiler infer the element type and count the items, but the result is a fixed-length array still.
I think this case is not common enough to deserve a third syntax.
Comment #7 by bugzilla — 2012-01-19T02:15:21Z
This is a very low priority issue.
Comment #8 by bearophile_hugs — 2012-01-19T04:46:56Z
(In reply to comment #7)
> This is a very low priority issue.
Well, I don't agree. It's a language design issue, so its priority is higher than most implementation matters.
Comment #9 by thelastmammoth — 2012-04-30T14:37:52Z
(In reply to comment #8)
> (In reply to comment #7)
> > This is a very low priority issue.
>
> Well, I don't agree. It's a language design issue, so its priority is higher
> than most implementation matters.
See proposal [Issue 8008] for a simpler alternative: auto x=[1,2,3]S (or auto x=[1,2,3]f).
I believe it makes [$] mostly irrelevant, and has other advantages.
Comment #10 by lovelydear — 2012-04-30T14:51:42Z
(In reply to comment #8)
> (In reply to comment #7)
> > This is a very low priority issue.
>
> Well, I don't agree. It's a language design issue, so its priority is higher
> than most implementation matters.
I fully agree with Walter Bright.
Sorry to be blunt here but this whole discussion is absolutely pointless and should be closed as WONTFIX right now. People have better things to do.
If some dude can't count the number of elements he puts in his 10 elements array initializer, he'd better stop programming at all. Introducing some strange Perl-like syntax for that is madness.
Comment #11 by bearophile_hugs — 2012-04-30T17:04:35Z
(In reply to comment #10)
> Sorry to be blunt here but this whole discussion is absolutely pointless and
> should be closed as WONTFIX right now. People have better things to do.
It's relevant, also because there are 6 votes.
> If some dude can't count the number of elements he puts in his 10 elements
> array initializer, he'd better stop programming at all. Introducing some
> strange Perl-like syntax for that is madness.
Thank you for your note, it allows me to better express why this issue relevant.
It's not DRY (http://en.wikipedia.org/wiki/DRY ), and duplicated information tends to get out of sync (and this causes bugs).
You write (think of a as a longer array):
int[5] arr = [1,2,3,4,5];
void main() {}
Later you change the code and your remove on item from the literal, but you forget to update the array size on the left:
int[5] arr = [1,2,4,5];
void main() {}
The compiler gives you no error nor warning, and arr actually contains [1,2,4,5,0]. This is a source of bugs, it has happened to me too.
With a syntax like [$] or []S it can't happen, because the length is not stated twice.
Comment #12 by hsteoh — 2012-04-30T17:21:24Z
(In reply to comment #10)
[...]
> If some dude can't count the number of elements he puts in his 10 elements
> array initializer, he'd better stop programming at all. Introducing some
> strange Perl-like syntax for that is madness.
You're totally missing the point. Code like this is very prone to bugs:
int[5] x = [1,2,3,4,5];
because as soon as somebody edits the list of elements, the count will be wrong. Restating something that the compiler already knows is a bad idea. (The same problem occurs in C/C++; in the C case, depending on the compiler, you may even get a gratuitous array overrun.)
The proposed int[$] = [ ... ]; is a very good solution, because $ already means "length of array" in D, and would fit seamlessly into the existing language.
Comment #13 by thelastmammoth — 2012-04-30T17:38:59Z
(In reply to comment #11 and comment #12)
I agree with the need for some syntactic sugar for static array literal, but is there any scenario where the postfix literal "auto x=[1,2,3]S" (or [1,2,3]f if you prefer) proposed in [Issue 8008] doesn't advantageously replace int[$]x=[1,2,3]? (more generally to force type T in case of ambiguity we can write [cast(T)1,2,3]S but usually not necessary with 1u,1f etc).
The advantage of [1,2,3]S over [$] or the current situation being that:
1) we can directly pass a static array to a function without requiring an intermediate static array declaration (int[$]x=[1,2,3]; fun(x); becomes simply fun([1,2,3]S);
2) from my understanding, there is still an intermediate heap allocation with the current int[3]=[1,2,3]; please correct me if I'm wrong), which should be easier to avoid with [1,2,3]S).
(As an optional bonus, would it also be easy to implement implicit casts with [...]S ? eg
void fun(in double[3] x){...}
fun([1,2,3]S); //should do implicit cast to double[3];
//the implicit casts should follow the same rules as for numeric values. )
Comment #14 by bearophile_hugs — 2012-08-10T20:03:23Z
A bug I've just found. Originally I was using 20 points, and I needed them in a fixed-size array. Later I have removed some of them to reduce the testing time, but I have forgotten to update the number of items in P[20].
The compiler gives me no compilation errors (it gives errors only if the number is less than the number of given items), the missing array items are filled with P(0,0) by the compiler, the duplicated zero points produce an almost correct result, but not exactly correct, so I have to spend minutes to spot the problem. This is the minimized code, that shows this simple bug the compiler isn't able to find for me:
import std.typecons;
alias Tuple!(int, int) P;
enum P[20] a = [P(62, -67), P(4, -71), P(-86, 71), P(-25, -53), P(-23, 70),
P(46, -34), P(-92, -62), P(-15, 89), P(100, 42), P(-4, 43),
P(21, 59), P(86, -25), P(93, -52), P(-41, -48), P(-45, 76),
P(85, -43), P(-69, 64)];
void main() {}
Comment #15 by rswhite4 — 2013-05-31T08:02:10Z
int arr[$] = [1,2,3,4]; // makes an int[4]
Looks pretty nice and I wish something like this often.
Any chance that we get this in the near future (maybe with 2.064)?
Comment #16 by samjnaa — 2013-05-31T10:37:21Z
FWIW I vote for using int[$] a = [ 1,2,3,4 ] syntax for this. auto[$] would of course also be valid to allow compile-time type inference.
Comment #17 by bearophile_hugs — 2013-10-01T18:35:33Z
Huh, I thought this PR was reverted because Andrei/Walter didn't like it; why is it being pulled into the 2.067 branch?
Comment #31 by eco — 2015-02-20T03:15:22Z
(In reply to hsteoh from comment #30)
> Huh, I thought this PR was reverted because Andrei/Walter didn't like it;
> why is it being pulled into the 2.067 branch?
Just because it's in the git commit history. The revert was also merged.
Comment #32 by samjnaa — 2015-10-11T15:21:00Z
(In reply to hsteoh from comment #30)
> Huh, I thought this PR was reverted because Andrei/Walter didn't like it;
> why is it being pulled into the 2.067 branch?
What is not to like about it? Walter only said in comment #7 that he thought it was low priority. What is unacceptable about the PR or even of the concept itself? DRY is a very sane principle and other users have clearly shown use cases where it will help to avoid errors.
Comment #33 by ketmar — 2015-10-12T03:03:48Z
don't worry, the patch was quickly reversed. it's simply bugzilla cannot automaticaly track reverts.
Comment #34 by samjnaa — 2015-10-12T05:39:10Z
(In reply to Ketmar Dark from comment #33)
> don't worry, the patch was quickly reversed. it's simply bugzilla cannot
> automaticaly track reverts.
Sorry if I'm being dense – it's not intentional. *Which* patch was reversed? IIUC the PR was intended to *add* this feature. Are you saying that it was first pulled, then reversed and then reversed again, meaning that the feature was finally actually added?
IIUC as per the last github post in the bugzilla which points to Andrei pulling the PR: https://github.com/D-Programming-Language/dmd/commit/fa296e9f088e0e3ccc9f339423bbef15cb3840aa, the main file modified was declaration.c, but apparently there is no such file any longer under master https://github.com/D-Programming-Language/dmd/tree/master/src, so I'm not sure under which branch the feature was included...
Putting it another way, will we get this feature with 2.069?
Thanks for your patience!
Comment #35 by ketmar — 2015-10-12T05:50:24Z
sorry, i messed dates. :-)
the `[$]` patch was first merged, and then reverted. this feature will not be in D2, ever: it was decided that one can do almost the same thing with some template magic. it was decided by W&A, so there's no reason to argue if this feature should be included, Masters says their word on it.
Comment #36 by samjnaa — 2015-10-13T01:57:44Z
(In reply to Ketmar Dark from comment #35)
> sorry, i messed dates. :-)
>
> the `[$]` patch was first merged, and then reverted. this feature will not
> be in D2, ever: it was decided that one can do almost the same thing with
> some template magic. it was decided by W&A, so there's no reason to argue if
> this feature should be included, Masters says their word on it.
Sorry, but I don't think "masters' word" is a technically valid reason for rejecting the request outright. No matter how much work someone put into the language and its compiler, just saying no without saying why or what else can be done is not acceptable. It simply rubs community people the wrong way. If this particular patch's approach to the problem wasn't acceptable, that's a different thing, but the idea itself is most sane and I don't see any reasons provided as to why it should be rejected.
Further, I don't get how Walter/Andrei are supposed to have nixed this. Below in comment #1, Andrei only has something positive to say about this, and neither he nor Walter have said anything negative...
Comment #37 by ketmar — 2015-10-13T02:00:13Z
you are welcome to search NG for heated discussions. this issue is setteld down, so there's no reason to argue anymore. alas.
Comment #38 by samjnaa — 2015-10-13T10:44:03Z
Hmmm. I read through the thread starting at http://forum.dlang.org/post/[email protected]. I think I sorta see the point of the developers here.
While I still think [$] is a cool little tidbit, I also have to agree with the comment which said "let's not add every little tidbit to the language". The title of the request is "letting compiler determine length for fixed-length arrays", not specifically to add [$]. Having the compiler determine the length can be done in many ways, and given that I already have to go to the library for a lot of commonly used stuff like writeln and to!, this one doesn't seem too much more. Although it *does* seem like something you should have out of the box, so do stuff like print()... :-)
The one thing the library solution probably cannot address would be the convoluted examples like a fixed-size array of a dynamic array of fixed-size arrays, but let's face it: those are really contrived examples and not worth introducing a language feature for...
I'm leaving my votes in since I do want *something* to be done to address the actual request, since any such library solution is ATM still sitting over at http://dpaste.dzfl.pl/f49a97e35974 and not actually included in Phobos.
BTW I don't think it should be named just 's' in the std.array module, but something more meaningful, like fixedLengthArray (yikes, yes I know, but I'm open to suggestions) and one can always do something like:
import std.array: f = fixedLengthArray;
Comment #39 by ketmar — 2015-10-13T10:55:53Z
tbh, i don't really care, as i've integrated this patch into my private dmd build long time ago and i'm happy with it. so i have no opinion here (yes, i know that "my D" is incompatible with "official D", so what? :-).
Comment #40 by rswhite4 — 2015-10-13T11:04:07Z
(In reply to Shriramana Sharma from comment #38)
> Hmmm. I read through the thread starting at
> http://forum.dlang.org/post/[email protected]. I think I sorta
> see the point of the developers here.
>
> While I still think [$] is a cool little tidbit, I also have to agree with
> the comment which said "let's not add every little tidbit to the language".
> The title of the request is "letting compiler determine length for
> fixed-length arrays", not specifically to add [$]. Having the compiler
> determine the length can be done in many ways, and given that I already have
> to go to the library for a lot of commonly used stuff like writeln and to!,
> this one doesn't seem too much more. Although it *does* seem like something
> you should have out of the box, so do stuff like print()... :-)
>
> The one thing the library solution probably cannot address would be the
> convoluted examples like a fixed-size array of a dynamic array of fixed-size
> arrays, but let's face it: those are really contrived examples and not worth
> introducing a language feature for...
>
> I'm leaving my votes in since I do want *something* to be done to address
> the actual request, since any such library solution is ATM still sitting
> over at http://dpaste.dzfl.pl/f49a97e35974 and not actually included in
> Phobos.
>
> BTW I don't think it should be named just 's' in the std.array module, but
> something more meaningful, like fixedLengthArray (yikes, yes I know, but I'm
> open to suggestions) and one can always do something like:
>
> import std.array: f = fixedLengthArray;
There is a better way:
----
import std.stdio;
pragma(inline, true);
auto s(T, size_t n)(auto ref T[n] arr) {
return arr;
}
void main() {
auto arr = [1, 2, 3].s;
writeln(typeof(arr).stringof);
}
---
Comment #41 by razvan.nitu1305 — 2017-11-01T15:58:56Z
should this be closed?
Comment #42 by andrei — 2017-11-01T23:49:02Z
(In reply to RazvanN from comment #41)
> should this be closed?
Let's keep it open until a library implementation is merged. I'll change the title.