I need get the type of container item(seq, array, iterator etc), so I write an template to get the item type, but when work with the generic, sometime it will fail to compile using the wrapper. Here is the code

import macros

template getTypeOfItem(t: untyped): auto =
   type(t[0])

template getType(t: untyped): auto =
   type(t[0])

template foo1(t: untyped) =
   var x: type(t[0])

template foo2(t: untyped) =
   var x: getType(t)

template foo3(t: untyped) =
   var x: getTypeOfItem(t)

proc foo[T](x: seq[seq[T]]) =
   foo1(x)     # this works
   
   foo2(x)     # this works too if we import the macros
               # without import macros, it fail to compile too
               # because there is proc in the macros named getType
               # very strange why it affect
   
   foo3(x)     # this works for non generic function
               # but it fail in this function

foo(@[@[1,2], @[3,4]])

My question is:

  1. Is there a way to make the foo3(x) compile?
  2. Why the foo2(x) compiles when import the macros, it seems very strange?

Thank you.

2017-05-09 09:32:36

The compiler show the following message:

ttype.nim(29, 4) template/generic instantiation from here

ttype.nim(16, 24) Error: type expected

2017-05-09 09:34:52

I don't quite understand what you are trying to achieve, something like this or no?

import typetraits

template underlyingType[T](a:seq[T]): typedesc =
   when T is seq:
     underlyingType(a[0])
   else:
     T

let a = @[1,2,3]
let b = @[a, a]

echo underlyingType(a).name # prints int
echo underlyingType(b).name # prints int

2017-05-09 11:34:17

@cdome Thank you.

I am writing function like map, it will take the type array, slice, seq, iterator, etc as parameter, because the iterator cannot be treated as typed, so I cannot use typed(If the paramter type is typed, the function in the code can compile successfully).

The code like this works:

type outType = type((
      block:
         when compiles(seq1.len) and not (seq1 is string):
            when seq1 is array[1, Slice]: (var it{.inject.}: type(seq1[0].a);)
            else: (var it{.inject.}: type(seq1[0]);)
         elif seq1 is Slice: (var it{.inject.}: type(seq1.a);)
         else: (var it{.inject.}: type(seq1);)
         op))
   var result: seq[outType] = @[]

I have several function like this, so I hope I can use an template to wrapper the code rather than copy/paste, but if I put the code in another template, I get the compiler error.

2017-05-09 13:22:13
Sounds it is easier to have multiple map functions for different types and let compiler to decide using signature matching which one is the best fit 2017-05-09 13:54:36
@cdome That doesn't work, because iterator is treated as untyped, and untyped parameter cannot be overloaded. The following code cannot compile.
proc f1(t: seq[int]) = discard
template f1(t: untyped) = discard

f1(@[1])
f1(countup(1,3))
2017-05-10 00:21:45
@slangmgh, accumulateResult cannot help?
2017-05-10 00:33:33
@mashingan Yes, I can convert the iterator to seq and all works. But it not the way I want. I hope the iterator is same as seq, like following code:
print collectz(1..5, @[toSeq(1..it)])
print collectz(@[1,2,3], @[toSeq(1..it)])
print collectz(countup(1,4), @[toSeq(1..it)])
print collectz(x <- 1..5, @[toSeq(1..x)])
print collectz(x <- @[1,2,3], @[toSeq(1..x)])
print collectz(x <- countup(1,4), @[toSeq(1..x)])
2017-05-10 00:50:56
The issue with foo2 and foo3 is one and the same: when called from a generic proc, untyped-arguments templates in them won't be used for type annotations. Your getType is not used then, so macros's one used, if you import it, what you can see by using explicit your_module_name.getType - then import macros will change nothing.
2017-05-11 05:51:26

@LeuGim

One little question. When I import the macros, the getType of this file is used, not the macros's getType, this is strange. That's mean import macros affect the template in this file can be used or not.

2017-05-12 00:37:17
<<<••12••>>>