www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - API

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
So I'm looking at creation functions and in particular creation 
functions for arrays.

1. Follow the new int[n] convention:

auto a = allok.make!(int[])(42);
assert(a.length == 42);
assert(a.equal(repeat(0, 42));

2. Follow the [ literal ] convention:

auto a = allok.make!(int[])(42);
assert(a.length == 1);
assert(a[0] == 42);

For the second option, to create longer arrays:

auto a = allok.make!(int[])(42, 43, 44);
assert(a.length == 3);
assert(a.equal(iota(42, 45));

Nice ways to repeat things:

auto a = allok.make!(int[])(42, repeat(43, 5), 44);

And even nice ways to create holes for efficiency:

auto a = allok.make!(int[])(42, uninitialized(5), 44);


Destroy.

Andrei
May 05 2014
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 1. Follow the new int[n] convention:
 2. Follow the [ literal ] convention:

We could combine these pretty easily: struct Length { size_t length; } allok.make!(int[])(Length(42)); // #1 allok.make!(int[])(1,2,3); // #2 btw could also use IFTI here which is nice This also potentially gives a third option: allok.make!(Length(42), 5); // length == 42, all elements == 5, typeof(return) == typeof(args[1])[] I kinda like that, though I'm not sure if I'd still like it if I used it regularly. Then, of course, we can also take other ranges to initialize too.
May 05 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
I guess if it takes an input range with lengths though it could 
just as well do alloc.make(repeat(0).take(45))
May 05 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 So I'm looking at creation functions and in particular creation 
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

Both cases are needed. Unfortunately we don't have named arguments in D, otherwise you can use the same name for both operations, using different arguments. Also keep in mind that in std.array we have functions like assocArray, uninitializedArray, and minimallyInitializedArray. I suggest to take a look at a similar function in Scala and especially in Lisp. Lisp has decades of experience to steal from. A common desire is to create an array based on a given function of its indexes: immutable a = allok.make!(int[][])(tuple(2, 3), (r, c) => r * 10 + c); ==> [[0, 1, 2], [10, 11, 12]] This is rather handy when you want to create immutable arrays.
 auto a = allok.make!(int[])(42, uninitialized(5), 44);

From my experience this is a very uncommon situation, I don't remember if I have ever had such need. (In most cases you want an initialized or an unitialized array. More rarely you want to initialize the first N items and leave M items not initialized). Bye, bearophile
May 05 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I guess if it takes an input range with lengths though it could 
 just as well do alloc.make(repeat(0).take(45))

This is OK if "make" recognizes the repeat.take type statically and uses this information to allocate the array efficiently. In general such pattern recognition tricks should be more present in Phobos (in Haskell there is even a syntax to add them). Bye, bearophile
May 05 2014
prev sibling next sibling parent "Brian Schott" <briancschott gmail.com> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation 
 functions for arrays.

 1. Follow the new int[n] convention:

I prefer this one.
May 05 2014
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Tue, May 06, 2014 at 12:28:19AM +0000, bearophile via Digitalmars-d wrote:
 Andrei Alexandrescu:
 
So I'm looking at creation functions and in particular creation
functions for arrays.

1. Follow the new int[n] convention:

auto a = allok.make!(int[])(42);
assert(a.length == 42);
assert(a.equal(repeat(0, 42));

2. Follow the [ literal ] convention:

auto a = allok.make!(int[])(42);
assert(a.length == 1);
assert(a[0] == 42);

Both cases are needed. Unfortunately we don't have named arguments in D, otherwise you can use the same name for both operations, using different arguments.

Adam's trick with a Length struct neatly solves this problem. :-) struct Length { size_t n; } auto a = allok.make!(int[])(Length(42), 1); ... // etc It's a very clever idea, and I like it! T -- In theory, software is implemented according to the design that has been carefully worked out beforehand. In practice, design documents are written after the fact to describe the sorry mess that has gone on before.
May 05 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 6 May 2014 at 00:31:04 UTC, bearophile wrote:
 This is OK if "make" recognizes the repeat.take type statically 
 and uses this information to allocate the array efficiently.

I don't think it needs any special beyond hasLength!T so it can allocate it all in one go, so it wouldn't be specialized on Take specifically, just anything with an explicit length property.
May 05 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I don't think it needs any special beyond hasLength!T so it can 
 allocate it all in one go, so it wouldn't be specialized on 
 Take specifically, just anything with an explicit length 
 property.

If you know that the item is always the same (coming from a repeat) can't you optimize the memory filling better? Bye, bearophile
May 05 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 6 May 2014 at 00:39:44 UTC, bearophile wrote:
 If you know that the item is always the same (coming from a 
 repeat) can't you optimize the memory filling better?

Oh yeah, that's a good point, you can similarly optimize if you know the size of the copy that's needed at compile time (generate better inline memcpy code).
May 05 2014
prev sibling next sibling parent "Idan Arye" <GenericNPC gmail.com> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation 
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

 For the second option, to create longer arrays:

 auto a = allok.make!(int[])(42, 43, 44);
 assert(a.length == 3);
 assert(a.equal(iota(42, 45));

 Nice ways to repeat things:

 auto a = allok.make!(int[])(42, repeat(43, 5), 44);

 And even nice ways to create holes for efficiency:

 auto a = allok.make!(int[])(42, uninitialized(5), 44);


 Destroy.

 Andrei

The first option should have better performance(write fast code). The second method allows more expressiveness(write code fast). I generally like expressiveness, but direct memory allocation is low level programming, so fast code should take precedence.
May 05 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/5/2014 5:10 PM, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation functions for
 arrays.

My bikeshed color comments: 1. "allok" is too kute for a name. Rather have "allocate" or "alloc". 2. why "make" instead of "construct" or "factory"?
May 05 2014
next sibling parent "MattCoder" <idonthaveany mail.com> writes:
On Tuesday, 6 May 2014 at 00:54:33 UTC, Walter Bright wrote:
 On 5/5/2014 5:10 PM, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular 
 creation functions for
 arrays.

My bikeshed color comments:

 2. why "make" instead of "construct" or "factory"?

Or "build" ? Matheus.
May 05 2014
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/5/14, 5:54 PM, Walter Bright wrote:
 On 5/5/2014 5:10 PM, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation
 functions for
 arrays.

My bikeshed color comments: 1. "allok" is too kute for a name. Rather have "allocate" or "alloc".

Fortunately that's not part of the API, just of the example.
 2. why "make" instead of "construct" or "factory"?

Shorter. Andrei
May 05 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/5/2014 7:51 PM, Andrei Alexandrescu wrote:
 On 5/5/14, 5:54 PM, Walter Bright wrote:
 2. why "make" instead of "construct" or "factory"?


"Less" is 4 characters. I win!
May 05 2014
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/5/14, 9:56 PM, Walter Bright wrote:
 On 5/5/2014 7:51 PM, Andrei Alexandrescu wrote:
 On 5/5/14, 5:54 PM, Walter Bright wrote:
 2. why "make" instead of "construct" or "factory"?


"Less" is 4 characters. I win!

Semantics suk. -- Andrei
May 05 2014
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 6 May 2014 at 04:56:10 UTC, Walter Bright wrote:
 On 5/5/2014 7:51 PM, Andrei Alexandrescu wrote:
 On 5/5/14, 5:54 PM, Walter Bright wrote:
 2. why "make" instead of "construct" or "factory"?


"Less" is 4 characters. I win!

There's a precedent for "make" in "std.container". For what it's worth.
May 07 2014
prev sibling next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation 
 functions for arrays.

I like Adam's input range idea. It gives you the best of both worlds, I think. It clears the conflict between ints and lengths using an interface.
 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

auto a = allok.make(repeat(int.init).take(42)) A bit verbose but a shortcut could be added. I believe you may have proposed a second length argument to repeat before which would be nice and clean with UFCS, e.g., int.init.repeat(42).
 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

auto a = allok.make(42); // maybe require only() or don't use IFTI.
 For the second option, to create longer arrays:

 auto a = allok.make!(int[])(42, 43, 44);
 assert(a.length == 3);
 assert(a.equal(iota(42, 45));

auto a = allok.make(iota(42, 45));
 Nice ways to repeat things:

 auto a = allok.make!(int[])(42, repeat(43, 5), 44);

auto a = allok.make(42, repeat(43).take(5), 44); // recognize RoRs and expand them (or joiner() with only()
 And even nice ways to create holes for efficiency:

 auto a = allok.make!(int[])(42, uninitialized(5), 44);

uninitialized would be useful. Maybe uninitialized!int.take(5) to keep with the theme though I haven't fully considered if that would penalize performance.
 Destroy.

 Andrei

One last thought. If array() accepted a second argument for an allocator you could just use a lot of existing code and slap an allocator into that final argument on your UFCS chain. auto arr = iota(1, 5).joiner(only(7, 13)).array(allok);
May 05 2014
prev sibling next sibling parent "ed" <sillymongrel gmail.com> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation 
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

 For the second option, to create longer arrays:

 auto a = allok.make!(int[])(42, 43, 44);
 assert(a.length == 3);
 assert(a.equal(iota(42, 45));

 Nice ways to repeat things:

 auto a = allok.make!(int[])(42, repeat(43, 5), 44);

 And even nice ways to create holes for efficiency:

 auto a = allok.make!(int[])(42, uninitialized(5), 44);


 Destroy.

 Andrei

Does it have to be one function? allok.makeLength!(int[])(42) as per new int[n] convention allok.makeUsing!(int[])(42, 43, 44) as per literal convention s/makeUsing/makeFilled -- or just makeFill s/makeUsing/makeFrom s/makeUsing/makeWith etc. etc. Cheers, Ed
May 05 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Brad Anderson:

 I like Adam's input range idea. It gives you the best of both
 worlds, I think. It clears the conflict between ints and lengths
 using an interface.

I don't like it a lot. I think I'd like two differently named functions. I am not sure.
 One last thought. If array() accepted a second argument for an
 allocator you could just use a lot of existing code and slap an
 allocator into that final argument on your UFCS chain.

 auto arr = iota(1, 5).joiner(only(7, 13)).array(allok);

This is a nice idea. What about std.array.uninitializedArray and std.array.minimallyInitializedArray? Bye, bearophile
May 06 2014
prev sibling next sibling parent Orvid King via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 5/5/14, Adam D. Ruppe via Digitalmars-d <digitalmars-d puremagic.com> wrote:
 On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 1. Follow the new int[n] convention:
 2. Follow the [ literal ] convention:

We could combine these pretty easily: struct Length { size_t length; } allok.make!(int[])(Length(42)); // #1 allok.make!(int[])(1,2,3); // #2 btw could also use IFTI here which is nice This also potentially gives a third option: allok.make!(Length(42), 5); // length == 42, all elements == 5, typeof(return) == typeof(args[1])[] I kinda like that, though I'm not sure if I'd still like it if I used it regularly. Then, of course, we can also take other ranges to initialize too.

I actually think this is a very elegant solution, but does open the question, should `allok.make!(42)` create an array initialized to 42, or an array with length of 42? Provided this is documented, I don't think the ambiguity should be an issue.
May 06 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 05 May 2014 20:10:35 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 So I'm looking at creation functions and in particular creation  
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

case 1. allok.arrayOf!int(42); Yes, I know I got rid of the array type as the template parameter, but I don't think we want to duplicate the problem of not being able to allocate arrays on the heap that we have with 'new'. case 2. allok.array(42); // Use IFTI This mirrors std.array.array In fact, 2 really should be in std.array: array(Allocator, T...)(Allocator allok, T t) if (isAllocator!Allocator) -Steve
May 06 2014
prev sibling next sibling parent "Yota" <yotaxp thatGoogleMailThing.com> writes:
On Tuesday, 6 May 2014 at 00:10:36 UTC, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation 
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

I'm not a fan of the dual purposing at all. When I see "a.make!T(x, y, z)", I expect that to be identical to "new T(x, y, z)", whether T is an array type or not. The special case will cause more confusion than aid. I'd much prefer separate functions, as others had suggested. "a.zeroArray!int(dim1, dim2)"
May 06 2014
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/5/14, 5:10 PM, Andrei Alexandrescu wrote:
 So I'm looking at creation functions and in particular creation
 functions for arrays.

A few thoughts on the ideas so far (awesome ones, thanks!). Credit is implied to the respective posters.
 struct Length { size_t length; }

 allok.make!(int[])(Length(42)); // #1
 allok.make!(int[])(1,2,3); // #2 btw could also use IFTI here which is nice

 This also potentially gives a third option:

 allok.make!(Length(42), 5); // length == 42, all elements == 5, typeof(return)
== typeof(args[1])[]

This is interesting, and may be used later in other places. The only problem I see it's not used in other places :o).
 alloc.make(repeat(0).take(45))

The problem here is it's unclear whether the intent is to allocate and initialize a range object, or an array of integers. There's no clarification an array is needed. alloc.make!(int[])(repeat(0).take(45)) or alloc.makeArray(repeat(0).take(45)) would work.
 immutable a = allok.make!(int[][])(tuple(2, 3), (r, c) => r * 10 + c);
 ==>
 [[0, 1, 2], [10, 11, 12]]

This is going a bit further from arrays into arrays of arrays, which would make array creation different when part of another array. That doesn't sit well, but then arrays of arrays may be special enough.
 2. why "make" instead of "construct" or "factory"?
 Or "build" ?

The converse might be asked, too. One argument is std.container already uses "make", as does Go. "construct" is too specific because what really happens is allocation and construction, and "factory" is a bit unfortunate because it's a noun (yes, I know, Object has it).
 auto a = allok.make(42); // maybe require only() or don't use
 IFTI.

This lookes like making an integer, initializing it with 42, and returning a pointer to it.
 auto a = allok.make(iota(42, 45));

This allocates an iota object dynamically.
 One last thought. If array() accepted a second argument for an
 allocator you could just use a lot of existing code and slap an
 allocator into that final argument on your UFCS chain.

 auto arr = iota(1, 5).joiner(only(7, 13)).array(allok);

This is a really nice complement for the .array idiom used so often at the end of pipelines. It's currently around the top of my preferences. So the full signature would be: auto array(R, A)(R range, auto ref A allok);
 Does it have to be one function?

 allok.makeLength!(int[])(42) as per new int[n] convention
 allok.makeUsing!(int[])(42, 43, 44) as per literal convention

 s/makeUsing/makeFilled -- or just makeFill
 s/makeUsing/makeFrom
 s/makeUsing/makeWith

This is down-to-earth but somewhat lacking in flexibility; every pattern needs its own function.
 I actually think this is a very elegant solution, but does open the
 question, should `allok.make!(42)` create an array initialized to 42,
 or an array with length of 42? Provided this is documented, I don't
 think the ambiguity should be an issue.

Neither, that should return an int* pointing to an int = 42.
 case 1. allok.arrayOf!int(42);

Noice.
 Yes, I know I got rid of the array type as the template parameter,
 but I don't think we want to duplicate the problem of not being able
 to allocate arrays on the heap that we have with 'new'.

 case 2. allok.array(42); // Use IFTI

 This mirrors std.array.array

 In fact, 2 really should be in std.array:

 array(Allocator, T...)(Allocator allok, T t) if
 (isAllocator!Allocator)

Yah. Andrei
May 06 2014
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
06-May-2014 04:10, Andrei Alexandrescu пишет:
 So I'm looking at creation functions and in particular creation
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

Have this primitive to keep it simple. (i.e. make => pass args to "ctor") Especially in the case of int[][][] and such.
 2. Follow the [ literal ] convention:

 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);

This option is std.array.array in a disguise or rather the builder pattern. Would be nice to have it separately from allocator. My argument is: a) It should work for any container. b) Is related not to an allocator but rather to the type of container (and its associated allocator). Arrays are unfortunately oblivious of allocators. -- Dmitry Olshansky
May 06 2014
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 06 May 2014 15:32:23 -0400, Dmitry Olshansky  =

<dmitry.olsh gmail.com> wrote:

 06-May-2014 04:10, Andrei Alexandrescu =D0=BF=D0=B8=D1=88=D0=B5=D1=82:=

 So I'm looking at creation functions and in particular creation
 functions for arrays.

 1. Follow the new int[n] convention:

 auto a =3D allok.make!(int[])(42);
 assert(a.length =3D=3D 42);
 assert(a.equal(repeat(0, 42));

Have this primitive to keep it simple. (i.e. make =3D> pass args to "ctor") Especially in the case of int[][][] and such.

I agree with the spirit of your idea, but not the implementation. make!T(args) should build an instance of that type on the heap, and then= = call it's constructor. In the case of T =3D=3D int[], it should mean put an int[] on the heap, = not = allocate a block, and give me an int[] reference to it. Array is a special case IMO, and deserves its own primitive. -Steve
May 06 2014
prev sibling parent reply Byron <byron.heads gmail.com> writes:
On Mon, 05 May 2014 17:10:35 -0700, Andrei Alexandrescu wrote:

 So I'm looking at creation functions and in particular creation
 functions for arrays.
 
 1. Follow the new int[n] convention:
 
 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

Why not use make for length only
 
 2. Follow the [ literal ] convention:
 
 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);
 

And build here for building up the array
May 07 2014
parent "Xiaoxi" <xiaoxi 163.com> writes:
On Wednesday, 7 May 2014 at 16:12:15 UTC, Byron wrote:
 On Mon, 05 May 2014 17:10:35 -0700, Andrei Alexandrescu wrote:

 So I'm looking at creation functions and in particular creation
 functions for arrays.
 
 1. Follow the new int[n] convention:
 
 auto a = allok.make!(int[])(42);
 assert(a.length == 42);
 assert(a.equal(repeat(0, 42));

Why not use make for length only
 
 2. Follow the [ literal ] convention:
 
 auto a = allok.make!(int[])(42);
 assert(a.length == 1);
 assert(a[0] == 42);
 

And build here for building up the array

would have been cool if something like this worked: template make(T : U[n], U, alias n) i.e int dim = 42; make!int[dim]
May 07 2014