# Type parameter used in annotation

**URL:** <https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922>\
**Category:** Help & Support\
**Created:** [September 6, 2022, 1:41pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922 "2022-09-06T13:41:49Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![homodeluna](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/homodeluna/32/1755_2.png) [@homodeluna](https://forum.crystal-lang.org/u/homodeluna)\
**Post date:** [September 6, 2022, 1:41pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/1 "2022-09-06T13:41:49Z")

</div>

I want to use a type alias in a generic type. but here I got into trouble:

```crystal
class OrderedMap( K , V)
  enum Color : UInt8
      BLACK
      RED
  end
  private RED = Color::RED
  private BLACK = Color::BLACK
  class Node(K1,V1)
     #......
  end

  alias PNode = Pointer(Node(K,V))
  
  @root : PNode = PNode.null
......
end

```

this doesn’t work :

```auto
In lib\ordered_map.cr:38:30

 38 | alias PNode = Pointer(Node(K,V))
                                 ^
Error: undefined constant K

```

I tried to translate it from c++

```nohighlight
class OrderedMap
    //struct Node ------ failed in crystal
    using pnode = *node<K,V> //the equivalent annotation

```

this type appears very often, so I do need a shorter name for it,instead of writing`Pointer(Node(K,V))` everywhere. Is there a better or just practicable way in crystal?

---

<div class="post-metadata">

**Author:** ![anon69898395](https://avatars.discourse-cdn.com/v4/letter/a/848f3c/32.png) [@anon69898395](https://forum.crystal-lang.org/u/anon69898395)\
**Post date:** [September 6, 2022, 2:23pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/2 "2022-09-06T14:23:06Z")

</div>

I think you would write just `Pointer(Node)`.  
But I think it won’t let you do a `Pointer` to `Node`.

Unfortunately I can’t tell you what you should use instead :(

---

<div class="post-metadata">

**Author:** ![homodeluna](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/homodeluna/32/1755_2.png) [@homodeluna](https://forum.crystal-lang.org/u/homodeluna)\
**Post date:** [September 6, 2022, 2:30pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/3 "2022-09-06T14:30:37Z")

</div>

I wold better use `alias MyNode = Node(K,V)` because `Node` is a subclass of `Reference`,so there’s no eed to use a pointer.

the fitst `insert` method seems like

```crystal
  def insert(key : K ,value : V) : self
    self.class.tree_insert(@root,key,value)
    self
  end
  protected def self.tree_insert(this : Node(K,V) ,key : K ,value : V,father : Node(K,V)? = nil)
    unless this
      this = Node(K,V).new(key,value)
      return
    end
    case cmp = key <=> this.key
    when cmp.zero?
      this.value = value
    else 
      new_node : Node(K,V)? = nil
      if cmp.positive?
        if this.right
          self.tree_insert(this.right,key,value,this)
        else
          new_node = this.right = Node(K,V).new(key,value,RED)
        end
      else cmp.negative?
        if this.left
          self.tree_insert(this.left,key,value,this)
        else
          new_node = this.left = Node(K,V).new(key,value,RED)
        end
      end
      if new_node && this.color.red? && father
        self.tree_recolor_balance(new_node.as(Node(K,V)),this.as(Node(K,V)),father.as(Node(K,V)))
      end
    end
  end

```

however, you can’t write this because when you assign this with a new object, you doesn’t change `@root`. so therefore the whole method did nothing:

```auto
PS C:\Users\homodeluna\Desktop\tests\cr_ordered_map> crystal spec
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>
#<OrderedMap(Int32, Int32):0x1c9b0250b40 @root=nil>

```

```auto

```

---

<div class="post-metadata">

**Author:** ![homodeluna](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/homodeluna/32/1755_2.png) [@homodeluna](https://forum.crystal-lang.org/u/homodeluna)\
**Post date:** [September 6, 2022, 2:43pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/4 "2022-09-06T14:43:58Z")

</div>

`Pointer(Node)` is also illegal:

```crystal
In lib\ordered_map.cr:39:25

 39 | alias PNode = Pointer(Node)
                            ^---
Error: can't use OrderedMap::Node(K1, V1) as a generic type argument yet, use a more specific type

```

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [September 6, 2022, 2:48pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/5 "2022-09-06T14:48:00Z")

</div>

Correct me if I’m wrong, but I’m pretty sure the gist of the problem is you can’t have an alias that uses generics from another type like that.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [September 6, 2022, 3:02pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/6 "2022-09-06T15:02:26Z")

</div>

Right. I don’t think there’s any way around this. You’ll just have to type a bit more. The implementation of `Hash(K, V)` has `Entry(K, V)` and we type `Entry(K, V)` in many places.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [September 6, 2022, 3:03pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/7 "2022-09-06T15:03:55Z")

</div>

Maybe you can use a method or a macro?

Like…

```crystal
macro pnode
  Pointer(Node(K, V))
end

```

It would also work if that’s a method.

---

<div class="post-metadata">

**Author:** ![homodeluna](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/homodeluna/32/1755_2.png) [@homodeluna](https://forum.crystal-lang.org/u/homodeluna)\
**Post date:** [September 6, 2022, 3:33pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/8 "2022-09-06T15:33:24Z")

</div>

`pnode` can’t be used in a type annotation, because this lower-case word isn’t regarded as a type:

```auto
protected def self.tree_insert(this : pnode ,key : K ,value : V,father =pnode.null)

In lib\ordered_map.cr:54:41

 54 | protected def self.tree_insert(this : pnode ,key : K ,value : V,father =pnode.null)
                                            ^
Error: unexpected token: "pnode"

```

maybe the best way up to now is to write`Pointer(Node(K,V))` every time I need.

about the `alias` command, is aliasing a type with type parameter just unpreferred?(I saw the hash implementation you do write `Entry` many times) or it’s just because this functionality is too far to implement? I thought such a function would be useful and has been implemented in many other languages.

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [September 6, 2022, 3:35pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/9 "2022-09-06T15:35:38Z")

</div>

Somewhat related: [Request for generic alias · Issue #2803 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/issues/2803)

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [September 6, 2022, 3:47pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/10 "2022-09-06T15:47:35Z")

</div>

The main issue is that types exist unrelated to type parameters.

If you have this:

```crystal
class Foo(K, V)
  class Bar
  end
end

```

Then the class `Bar` exists only once for all `Foo`. You can do things like `Foo::Bar` and it works just fine.

But if you introduce something like this:

```crystal
class Foo(K, V)
  alias Bar = Something(K, V)
end

```

then if you do `Foo::Bar`… what does that even mean? Maybe that’s an error and it tells you that `K` and `V` are unknown.

But then if you have a method inside foo:

```crystal
class Foo(K, V)
  def foo
    Bar.new
  end
end

```

how would the compiler (or user) know that the `K` and `V` to use for `Bar` have to be the ones for `Foo`? It’s not clear…

It’s just too complex to understand and implement in my opinion. Or put another way: we can live without this feature. We could implement it, but it’s far from trivial.

---

<div class="post-metadata">

**Author:** ![homodeluna](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/homodeluna/32/1755_2.png) [@homodeluna](https://forum.crystal-lang.org/u/homodeluna)\
**Post date:** [September 6, 2022, 4:10pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/11 "2022-09-06T16:10:51Z")

</div>

that means this alias is contradictory with the “class is namespace” design. If we divide the space by each composition of type parameter, you’ll get a grand number of namespaces.

Just a hypothesis, I prefer seperating the namespaces, where `Foo(Int32,Int32)::Bar` and `Foo(String,UInt32)::Bar` both exists on thier own, and on the other side,`Foo::Bar` without specifying a type parameter is ambiguious.

This route isn’t wide and flat, and will result into countless details.Generic methods, generic restrictions, overload between many generic methods with different restrictions, partial instantiation … it’s just like learning c++ again.

maybe there’s a simpler way.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [September 6, 2022, 9:48pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/12 "2022-09-06T21:48:42Z")

</div>

I suppose it would be _thinkable_ to have constants (which includes aliases and types) at the generic instance type scope. But this would require a special syntax to distinguish them from the uninstantiated metaclass scope.  
It’s probably not a very common use case, otherwise this problem would probably appeared more often.  
And there’s a simple solution, instead of using an alias, just use its expansion directly everywhere, and it should work as expected (if not, you’re in a wrong scope again).

---

<div class="post-metadata">

**Author:** ![beta-ziliani](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/beta-ziliani/32/1821_2.png) [@beta-ziliani](https://forum.crystal-lang.org/u/beta-ziliani)\
**Post date:** [September 8, 2022, 1:07pm UTC](https://forum.crystal-lang.org/t/type-parameter-used-in-annotation/4922/13 "2022-09-08T13:07:04Z")

</div>

As someone who misses this feature, I would consider the following:

```crystal
class Foo(K, V)
  alias Bar = Something(K, V)

  def foo : Bar
     Bar.new
  end
end

Foo::Bar.new # error can't infer the type parameters K, V for the generic class Something(K, V). Please provide them explicitly
Foo(Int32, String)::Bar.new # OK

```

(If we can be smarter with the error, then that’d be great)  
I know this is hard from a technical point of view, because alias aren’t just an expansion, but theoretically speaking I don’t see a problem with consider them “just” an expansion for this use case.
