# Add #nilable? to more macro types

**URL:** <https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273>\
**Category:** Crystal Contrib\
**Created:** [January 12, 2019, 8:18pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273 "2019-01-12T20:18:00Z")\
**Posts on this page:** 10\
**Page:** 1

<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:** [January 12, 2019, 8:18pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/1 "2019-01-12T20:18:00Z")

</div>

Currently it is a major pain to figure out if a method arg’s restriction is nilable or not since it could be a multitude of different types.

[https://play.crystal-lang.org/#/r/78lk](https://play.crystal-lang.org/#/r/78lk)

It would be _super_ helpful if additional types had a `.nilable?` that would return true if the type includes nil. Which would be like:

- `Union.types.any? &.==(::Nil)`
- `Generic.type_vars.any? &.==(::Nil)`
- `Path.resolve.nilable?`

---

<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:** [July 17, 2019, 1:14am UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/2 "2019-07-17T01:14:16Z")

</div>

@asterite I been looking into implementing this, however im having some trouble with the `Union` and `Generic`.

`interpret_argless_method(method, args) { BoolLiteral.new(types.any? &.==(::Nil)) }` It seems the type of each “type” is `ASTNode`, thus doesn’t match the check or anything so i had to do like.

```crystal
BoolLiteral.new(
  types.any? do |t|
    interpreter.resolve(t.as(Path)).as(TypeNode).type.nilable?
  end
)

```

I think ideally these would live on the ASTNodes themselves where each type implements the method as needed. Do you have any thoughts/ideas about this?

---

<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:** [July 17, 2019, 1:37am UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/3 "2019-07-17T01:37:05Z")

</div>

Your first snippet works almost perfectly except for the `Union` case, if you replace `decl.type.nilable?` with `decl.type.resolve.nilable?`. I think `resolve` is missing for `Union`. I’m not sure about adding `nilable?` to all AST nodes. And for `Union` I think you just need to interpret `resolve` for the union members.

(sorry if I misunderstood you)

---

<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:** [July 17, 2019, 2:01am UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/4 "2019-07-17T02:01:06Z")

</div>

I would be happy if i could just do that, Currently im doing like:

`{% nilable = (type.is_a?(Path) ? type.resolve.nilable? : (type.is_a?(Union) ? type.types.any?(&.resolve.nilable?) : (type.is_a?(Generic) ? type.resolve.nilable? : type.nilable?))) %}`

Yea its missing for `Union`. Would that just be like:

```auto
    def resolve(node : Union)
      type = @path_lookup.lookup_type(node, self_type: @scope, free_vars: @free_vars)
      TypeNode.new(type)
    end

    def resolve?(node : Union)
      resolve(node)
    rescue Crystal::Exception
      nil
    end

```

I dont really know what im doing.

---

<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:** [July 17, 2019, 12:22pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/5 "2019-07-17T12:22:49Z")

</div>

I’ll see if I can do it. But to be honest I’m not sure `resolve` was a good idea (though apparently it’s used all over the place in Lucky).

---

<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:** [July 17, 2019, 12:28pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/6 "2019-07-17T12:28:11Z")

</div>

My main use case for this just to have a common `.nilable?` method you can call on the various types in macro land. I don’t know what the options are for having something like that, but it would certainly be helpful versus having to do different things depending on what type it is.

---

<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:** [July 17, 2019, 12:40pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/7 "2019-07-17T12:40:54Z")

</div>

I’ll do it later today 👍

---

<div class="post-metadata">

**Author:** ![paulcsmith](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/paulcsmith/32/301_2.png) [@paulcsmith](https://forum.crystal-lang.org/u/paulcsmith)\
**Post date:** [July 17, 2019, 2:54pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/8 "2019-07-17T14:54:31Z")

</div>

Just heads up that we have removed most `resolve` calls in Lucky because it can cause annoying issues where you have cyclical requires. So I’d probably avoid that.

And thanks for making the common `nilable?` we’ve needed that in a number of places in Lucky! Another cool thing would be to have `types` available on `TypeDeclaration` even if not a Union. Right now we have to check if the type is a Union and then call `types` on it, otherwise call `type`. We’d love to do something like `type_declaration.types` and have it work for non-Unions too. That would clean up a ton of conditional code

[https://play.crystal-lang.org/#/r/78r9](https://play.crystal-lang.org/#/r/78r9)

```
macro what_types(type_declaration)
  {% if type_declaration.type.is_a?(Union) %}
    {% p type_declaration.type.types %}
  {% else %}
    {% p type_declaration.type %}
  {% end %}

  # Would be wonderful if we could do for Union and non-Union
  # But it fails
  {% p type_declaration.type.types %}
end

what_types hi : String | Int32
what_types hi : String
```

---

<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:** [July 17, 2019, 3:11pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/9 "2019-07-17T15:11:03Z")

</div>

Yeah, I think `types` returning an array of a single type for a `TypeNode` makes sense, for working uniformly with types 👍

---

<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:** [July 17, 2019, 9:07pm UTC](https://forum.crystal-lang.org/t/add-nilable-to-more-macro-types/273/10 "2019-07-17T21:07:20Z")

</div>

Done! [https://github.com/crystal-lang/crystal/pull/7970](https://github.com/crystal-lang/crystal/pull/7970)

Let me know if I got it right and what you think.
