API

Andrei Alexandrescu via Digitalmars-d digitalmars-d at puremagic.com
Tue May 6 10:41:22 PDT 2014


On 5/5/14, 5:10 PM, Andrei Alexandrescu wrote:
> So I'm looking at creation functions and in particular creation
> functions for arrays.
[snip]

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




More information about the Digitalmars-d mailing list