Re: Append to 'map' result

2017-07-05 Thread Jean-Louis Leroy via Digitalmars-d-learn

On Wednesday, 5 July 2017 at 01:43:46 UTC, Ali Çehreli wrote:

On 07/04/2017 05:52 PM, Jean-Louis Leroy wrote:

On Wednesday, 5 July 2017 at 00:28:01 UTC, Ali Çehreli wrote:

On 07/04/2017 04:57 PM, Jean-Louis Leroy wrote:

[...]
No time to dig deeper but this is because the two ranges that 
chain()
receives do not have a common type. (Rather, that type is 
'void'):


[...]




This is related to TypeInfo.init, which unfortunately is *not* 
the .init property in this case. :( Luckily, it will be fixed 
in 2.075. This is what object.d has:

[...]
So, unfortunately, most Phobos range functions cannot be used 
with TypeInfo as they would invariably touch ElementType. Here 
is a halfway workaround that uses each() instead of map(): :/


Aaah, so I was not doing anything wrong ;-)

I was trying to factor this code:

  foreach (i; k.interfaces) {
if (i.classinfo in classMap) {
  v.bases ~= classMap[i.classinfo];
}
  }
  if (k.base in classMap) {
v.bases ~= classMap[k.base];
  }

i.e. process the class base along with the interfaces in the same 
loop. I dwelled on it because my goal with this project is to 
learn (and evaluate) D.


Anyway, I am building my own graph of enriched ClassInfo objects; 
once that is done, I won't be impacted with the bug anymore.


Thanks for the diagnostic...

J-L




Re: Append to 'map' result

2017-07-04 Thread Ali Çehreli via Digitalmars-d-learn

On 07/04/2017 05:52 PM, Jean-Louis Leroy wrote:

On Wednesday, 5 July 2017 at 00:28:01 UTC, Ali Çehreli wrote:

On 07/04/2017 04:57 PM, Jean-Louis Leroy wrote:

[...]

No time to dig deeper but this is because the two ranges that chain()
receives do not have a common type. (Rather, that type is 'void'):

[...]


I suspect that that is the reason, although I checked in several ways
that I had ClassInfo elements on both sides. Ok, I'll keep looking
tomorrow with a fresh eye...


This is related to TypeInfo.init, which unfortunately is *not* the .init 
property in this case. :( Luckily, it will be fixed in 2.075. This is 
what object.d has:


class TypeInfo
{
// ...

/**
 * Return default initializer.  If the type should be initialized 
to all
 * zeros, an array with a null ptr and a length equal to the type 
size will
 * be returned. For static arrays, this returns the default 
initializer for

 * a single element of the array, use `tsize` to get the correct size.
 */
abstract const(void)[] initializer() nothrow pure const @safe @nogc;

/// $(RED Removed.) Please use `initializer` instead.
@disable static const(void)[] init(); // since 2.074
/* Planned for 2.075: Remove init, making way for the init type 
property,

fixing issue 12233. */
}

The problem is, ElementType relies on .init, which works on most other 
type but not TypeInfo:


template ElementType(R)
{
static if (is(typeof(R.init.front.init) T))
alias ElementType = T;
else
alias ElementType = void;
}

So, unfortunately, most Phobos range functions cannot be used with 
TypeInfo as they would invariably touch ElementType. Here is a halfway 
workaround that uses each() instead of map(): :/


import std.algorithm;

class C {
}

void main() {
auto k = C.classinfo;

TypeInfo_Class[] arr;

each!(i => arr ~= i.classinfo)(k.interfaces);
arr ~= k.base;
}

Ali



Re: Append to 'map' result

2017-07-04 Thread Jean-Louis Leroy via Digitalmars-d-learn

On Wednesday, 5 July 2017 at 00:28:01 UTC, Ali Çehreli wrote:

On 07/04/2017 04:57 PM, Jean-Louis Leroy wrote:

[...]
No time to dig deeper but this is because the two ranges that 
chain() receives do not have a common type. (Rather, that type 
is 'void'):


[...]


I suspect that that is the reason, although I checked in several 
ways that I had ClassInfo elements on both sides. Ok, I'll keep 
looking tomorrow with a fresh eye...


Re: Append to 'map' result

2017-07-04 Thread Ali Çehreli via Digitalmars-d-learn

On 07/04/2017 04:57 PM, Jean-Louis Leroy wrote:

On Tuesday, 4 July 2017 at 23:26:28 UTC, H. S. Teoh wrote:

On Tue, Jul 04, 2017 at 11:27:25PM +, Jean-Louis Leroy via
Digitalmars-d-learn wrote:

I want to create a range that consists of the result of a map()
followed by a value, e.g.:

  int[] x = [ 1, 2, 3];
  auto y = map!(x => x * x)(x);
  auto z = y ~ 99; // how???

I have tried several variations: convert 99 to a dynamic array, to a
range, convert range to dynamic array (couldn't even figure that
one); to no avail.

[...]

Try:

auto z = chain(y, only(99));


Thanks!

However, when I try to use this construct in my real code, I still have
a problem:

// k is a ClassInfo
chain(map!(i => i.classinfo)(k.interfaces), only(k.base))

meth.d(311): Error: template std.range.chain cannot deduce function from
argument types !()(MapResult!(__lambda3, Interface[]),
OnlyResult!(TypeInfo_Class, 1LU)), candidates are:
/usr/include/d/std/range/package.d(795):
std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 &&
allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
!is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) ==
void))



No time to dig deeper but this is because the two ranges that chain() 
receives do not have a common type. (Rather, that type is 'void'):


import std.algorithm;
import std.range;
import std.traits;

class C {
}

void main() {
auto k = C.classinfo;
auto m = map!(i => i.classinfo)(k.interfaces);
auto b = only(k.base);

// Types
alias M = typeof(m);
alias B = typeof(b);

// Element types
alias EM = ElementType!M;
alias EB = ElementType!B;

// Two of chain's constraints are satisfied:
static assert(isInputRange!M);
static assert(isInputRange!B);
// Now it needs to see a CommonType of range elements

pragma(msg, EM);// const(void)[]()
pragma(msg, EB);// const(void)[]()

pragma(msg, CommonType!(EM, EB)); // void

// For that reason, the following does not work:
// chain(m, b);
}

Ali




Re: Append to 'map' result

2017-07-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, July 04, 2017 23:50:57 Nicholas Wilson via Digitalmars-d-learn 
wrote:
> On Tuesday, 4 July 2017 at 23:27:25 UTC, Jean-Louis Leroy wrote:
> > I want to create a range that consists of the result of a map()
> >
> > followed by a value, e.g.:
> >   int[] x = [ 1, 2, 3];
> >   auto y = map!(x => x * x)(x);
> >   auto z = y ~ 99; // how???
> >
> > I have tried several variations: convert 99 to a dynamic array,
> > to a range, convert range to dynamic array (couldn't even
> > figure that one); to no avail.
> >
> > Help please...
>
> using
> auto y = x.map!(x => x * x).array;
> will work.

Yeah, that will convert the range to a dynamic array, but if you're looking
to do is append onto a range, then using chain like H.S. Teoh showed is
better. And even if you ultimately want a dynamic array, using chain and
then calling array on the result than allocating the array and then
appending to it as an array means that you're only going to allocate the
array once, whereas if you append to the array, you might end up causing it
to be reallocated (though if you're just appending a single element to it
it'll have the space unless in std.array.array allocates a dynamic array
with exactly the space required for its elements, which I doubt).

- Jonathan M Davis



Re: Append to 'map' result

2017-07-04 Thread Jean-Louis Leroy via Digitalmars-d-learn

On Tuesday, 4 July 2017 at 23:26:28 UTC, H. S. Teoh wrote:
On Tue, Jul 04, 2017 at 11:27:25PM +, Jean-Louis Leroy via 
Digitalmars-d-learn wrote:

I want to create a range that consists of the result of a map()
followed by a value, e.g.:

  int[] x = [ 1, 2, 3];
  auto y = map!(x => x * x)(x);
  auto z = y ~ 99; // how???

I have tried several variations: convert 99 to a dynamic 
array, to a range, convert range to dynamic array (couldn't 
even figure that one); to no avail.

[...]

Try:

auto z = chain(y, only(99));


Thanks!

However, when I try to use this construct in my real code, I 
still have a problem:


// k is a ClassInfo
chain(map!(i => i.classinfo)(k.interfaces), only(k.base))

meth.d(311): Error: template std.range.chain cannot deduce 
function from argument types !()(MapResult!(__lambda3, 
Interface[]), OnlyResult!(TypeInfo_Class, 1LU)), candidates are:
/usr/include/d/std/range/package.d(795):
std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && 
allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 
!is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, 
Ranges))) == void))






Re: Append to 'map' result

2017-07-04 Thread Nicholas Wilson via Digitalmars-d-learn

On Tuesday, 4 July 2017 at 23:27:25 UTC, Jean-Louis Leroy wrote:
I want to create a range that consists of the result of a map() 
followed by a value, e.g.:


  int[] x = [ 1, 2, 3];
  auto y = map!(x => x * x)(x);
  auto z = y ~ 99; // how???

I have tried several variations: convert 99 to a dynamic array, 
to a range, convert range to dynamic array (couldn't even 
figure that one); to no avail.


Help please...


using
   auto y = x.map!(x => x * x).array;
will work.


Re: Append to 'map' result

2017-07-04 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 04, 2017 at 11:27:25PM +, Jean-Louis Leroy via 
Digitalmars-d-learn wrote:
> I want to create a range that consists of the result of a map()
> followed by a value, e.g.:
> 
>   int[] x = [ 1, 2, 3];
>   auto y = map!(x => x * x)(x);
>   auto z = y ~ 99; // how???
> 
> I have tried several variations: convert 99 to a dynamic array, to a
> range, convert range to dynamic array (couldn't even figure that one);
> to no avail.
[...]

Try:

auto z = chain(y, only(99));


T

-- 
I don't trust computers, I've spent too long programming to think that they can 
get anything right. -- James Miller


Append to 'map' result

2017-07-04 Thread Jean-Louis Leroy via Digitalmars-d-learn
I want to create a range that consists of the result of a map() 
followed by a value, e.g.:


  int[] x = [ 1, 2, 3];
  auto y = map!(x => x * x)(x);
  auto z = y ~ 99; // how???

I have tried several variations: convert 99 to a dynamic array, 
to a range, convert range to dynamic array (couldn't even figure 
that one); to no avail.


Help please...