# Trying to locate the proper class in a macro

**URL:** <https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814>\
**Category:** Help & Support\
**Created:** [March 13, 2020, 5:13pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814 "2020-03-13T17:13:59Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![jwoertink](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jwoertink/32/50_2.png) [@jwoertink](https://forum.crystal-lang.org/u/jwoertink)\
**Post date:** [March 13, 2020, 5:13pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/1 "2020-03-13T17:13:59Z")

</div>

## Context

In Lucky, we say that all actions must return a `Lucky::TextResponse`, and if your action doesn’t, it’ll raise a compile-time error telling you.

## The Issue

Related: [https://github.com/luckyframework/lucky/issues/460#issuecomment-474616588](https://github.com/luckyframework/lucky/issues/460#issuecomment-474616588)

The error that’s raised is called from

```crystal
  private def handle_response(_response : T) forall T
    {%
      raise <<-ERROR
      #{@type} returned #{T}, but it must return a Lucky::Response.
      Try this...
        ▸ Make sure to use a method like `render`, `redirect`, or `json` at the end of your action.
        ▸ If you are using a conditional, make sure all branches return a Lucky::Response.
      ERROR
    %}
  end

```

But in this case, `@type` will actually return the last class listed in your directory of Actions.

Using this image, the actual error is in `Home::Index`, but `@type` returns `SignUps::New`.

 ![Screen Shot 2020-03-13 at 9.32.31 AM](https://canada1.discourse-cdn.com/flex036/uploads/crystal_lang/original/1X/3e4c4407471e4298f0ec02492467b8612140a29d.png)

Is there a way to somehow mark where this error is actually coming from? Or are there other macro variables available that may give insight in to return `Home::Index`?

---

<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:** [March 13, 2020, 5:48pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/2 "2020-03-13T17:48:31Z")

</div>

Any way that you can provide reduced code that reproduces the issue? I tried this:

```crystal
module Foo
  def foo
    response = bar
    handle_response(response)
  end

  private def handle_response(_response : String)
    puts "OKAY!"
  end

  private def handle_response(_response : T) forall T
    {%
      raise "#{@type} returned #{T}, but it must return a String."
    %}
  end
end

abstract class Base
end

class Bar < Base
  include Foo

  def bar
    "hello"
  end
end

class Baz < Base
  include Foo

  def bar
    1
  end
end

(Bar.new || Baz.new).foo

```

It works fine.

---

<div class="post-metadata">

**Author:** ![jwoertink](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jwoertink/32/50_2.png) [@jwoertink](https://forum.crystal-lang.org/u/jwoertink)\
**Post date:** [March 13, 2020, 8:20pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/3 "2020-03-13T20:20:20Z")

</div>

I’m not sure if this is exactly the same or not, but here’s my go at a minimal:

[https://play.crystal-lang.org/#/r/8pv9](https://play.crystal-lang.org/#/r/8pv9)

I have a feeling there’s a lot more going on just because of how Lucky works. I can try and make a minimal lucky app if that helps

This example just shows that it seems to always be the last one (which could get hairy if you have 100 classes…)  
Edit: [https://play.crystal-lang.org/#/r/8pvb](https://play.crystal-lang.org/#/r/8pvb)

---

<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:** [March 13, 2020, 8:45pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/4 "2020-03-13T20:45:51Z")

</div>

Oh, I see what’s going on. The thing is that `response = call` will be evaluated on the abstract type and so the type of `response` is `Int32 | String`. The `handle_response` provides an overload for `Int32` and another for `T`. The compiler doesn’t discards type from a union when an overload matches, so `T` here will be `Int32 | String`. And that will trigger for the base type and the error will be executed on all types, but only the first one (according to some ordering) will trigger the error, and so you get it on Four.

One way to solve it:

- Add a dummy `{% @type %}` on `run`. This will make it be a macro method, meaning that you will get a different method on each type, not one in the abstract type. It’s hacky but it works.

I’m thinking of other ways but I don’t know…

A proper solution might be to have a way to mark methods as “macro methods” like we used in the past. But it’s still pretty low-level.

---

<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:** [March 13, 2020, 8:53pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/5 "2020-03-13T20:53:26Z")

</div>

So like this: [https://play.crystal-lang.org/#/r/8pvc](https://play.crystal-lang.org/#/r/8pvc)

---

<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:** [March 13, 2020, 8:54pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/6 "2020-03-13T20:54:03Z")

</div>

But why not make `call` abstract and force a return type there? The compiler will do the work for you.

---

<div class="post-metadata">

**Author:** ![jwoertink](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jwoertink/32/50_2.png) [@jwoertink](https://forum.crystal-lang.org/u/jwoertink)\
**Post date:** [March 13, 2020, 9:08pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/7 "2020-03-13T21:08:12Z")

</div>

This comes from the macro methods

```auto
get "/whatever" do
  # must return Lucky::TextResponse here
end

```

I’ll have to dig in more to see if we can just let the compiler handle it. We might just have a missing type that will fix it all. I didn’t know throwing macro code in to a method makes that method a macro. I’ll play around with your suggest there and see where that takes me. Thanks!

---

<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:** [March 13, 2020, 9:19pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/8 "2020-03-13T21:19:30Z")

</div>

We definitely can use an abstract method and I thinks that what we ended up doing, but we’d like a better error message so people know what they need to do to fix it. If they see they need to return a `Lucky::Response` they may not know what to do.

---

<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:** [March 13, 2020, 9:23pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/9 "2020-03-13T21:23:16Z")

</div>

What I’d really love to see (and have proposed earlier but didn’t push that hard on) is a way to give custom messages that the compiler can use. But that’s probably whole different discussion.

I’d love something like

```
@[CrystalReturnError("message to give when return type doesn't match")]
def render : Lucky::Response
end

```

I have no idea how or if that would work, but something like that would be incredible

---

<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:** [March 13, 2020, 9:23pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/10 "2020-03-13T21:23:18Z")

</div>

> [@jwoertink](#):
>
> I didn’t know throwing macro code in to a method makes that method a macro.

That only happens when you mention `@type` inside a macro. The rationale behind that is that the method needs to be specialized depending on the `@type` so we make a separate instance for it, never reusing it if it’s, say, an abstract type and the method is not overridden in subclasses.

That’s why I suggested adding a dummy `{% @type %}`… but I suggest a good comment like “this makes Crystal generate this method separately for each different type”.

---

<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:** [March 13, 2020, 9:23pm UTC](https://forum.crystal-lang.org/t/trying-to-locate-the-proper-class-in-a-macro/1814/11 "2020-03-13T21:23:52Z")

</div>

Thanks for your help @asterite!! I hope this works
