# \`JSON::Serializable\` w/ Inheritance

**URL:** <https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613>\
**Category:** Help & Support\
**Created:** [May 7, 2022, 11:16pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613 "2022-05-07T23:16:51Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 7, 2022, 11:16pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/1 "2022-05-07T23:16:51Z")

</div>

I’m playing around with implementing ActivityPub where most of the entities over the JSON API inherit from other types. For example, `Create < Activity < Object`. And that works as long as I don’t define an `initialize` method that lets me instantiate them myself to be able to send the instances to other servers. This snippet illustrates what I’m trying to do:

```crystal
require "json"

abstract class A
  include JSON::Serializable

  getter a1 : String?
  getter a2 : String?

  def initialize(*, @a1 = nil, @a2 = nil)
  end
end

class B < A
  getter b1 : String? = nil

  def initialize(*, @b1 = nil, **kwargs)
    super(**kwargs)
  end
end

pp B.new(
  a1: "a1",
  b1: "b1",
)

pp B.from_json({
  a1: "a1",
  b1: "b1",
}.to_json)

```

This represents some superclass `A` that has a bunch of properties common to all ActivityPub objects, and then subclasses add extra ones. But it doesn’t compile:

```auto
Showing last frame. Use --error-trace for full trace.

In examples/stuff.cr:17:5

 17 | super(**kwargs)
      ^----
Error: no parameter named '__pull_for_json_serializable'

Matches are:
 - A#initialize(*, a1 = nil, a2 = nil)

shell returned 1

```

Are there some semantics I’m overlooking? Can anyone think of any workarounds?

---

<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:** [May 7, 2022, 11:20pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/2 "2022-05-07T23:20:23Z")

</div>

Just remove the `*` from your initializers and it’ll work. Alternatively, duplicate the params on each constructor/super call to avoid Crystal thinking you’re calling the `JSON::Serializable` overload.

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 7, 2022, 11:32pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/3 "2022-05-07T23:32:08Z")

</div>

> [@Blacksmoke16](#):
>
> Just remove the `*` from your initializers and it’ll work.

Unfortunately, this does not work. I still got the same error from this code:

```crystal
require "json"

abstract class A
  include JSON::Serializable

  getter a1 : String?
  getter a2 : String?

  def initialize(@a1 = nil, @a2 = nil)
  end
end

class B < A
  getter b1 : String? = nil

  def initialize(@b1 = nil, **kwargs)
    super(**kwargs)
  end
end

pp B.new(
  a1: "a1",
  b1: "b1",
)

pp B.from_json({
  a1: "a1",
  b1: "b1",
}.to_json)

```

> [@Blacksmoke16](#):
>
> Alternatively, duplicate the params on each constructor/super call to avoid Crystal thinking you’re calling the `JSON::Serializable` overload.

This does work, however, which is a bit surprising. I feel like since `kwargs` is known at compile time to be a `NamedTuple` with known keys, double-splatting it would know to call the `@a1 = nil, @a2 = nil` overload.

Something I just thought about while writing the above paragraph, though, is that in that overload, every argument is optional, and I wondered if that made a difference. So I experimented with removing some of the default `nil` values. It compiles as long as `@b1` is not an optional argument. Does this sound like a bug or is it unreasonable to expect the type checker to figure this out?

---

<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:** [May 7, 2022, 11:34pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/4 "2022-05-07T23:34:18Z")

</div>

> [@jgaskins](#):
>
> Unfortunately, this does not work. I still got the same error from this code:

Hmm, are you sure? [Carcin](https://play.crystal-lang.org/#/r/d55t) Seems to work fine no?

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 7, 2022, 11:35pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/5 "2022-05-07T23:35:07Z")

</div>

Oooh, I see, it’s not super obvious from the code snippet in the post but there’s more code if you scroll. Once you add the `.from_json` call, it stops compiling.

---

<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:** [May 7, 2022, 11:41pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/6 "2022-05-07T23:41:37Z")

</div>

Ahh okay, yea that does it. I think what’s ultimately happening is you’re redefining the initializer defined by `JSON::Serializable`, which `.from_json` ends up calling. Tho I’m not sure if this is expected or a bug given Crystal in other cases is able to figure it out: [Carcin](https://play.crystal-lang.org/#/r/d55z). So reducing the code to figure out what the trigger is might be helpful.

EDIT: By reduce I mean try and figure out what exact combination of constructors/inheritance causes it, or if its strictly related to the included module/inherited hook.

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 7, 2022, 11:53pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/7 "2022-05-07T23:53:00Z")

</div>

> [@Blacksmoke16](#):
>
> I think what’s ultimately happening is you’re redefining the initializer defined by `JSON::Serializable` , which `.from_json` ends up calling.

Ahh, that sounds right. I seem to remember something built into `JSON::Serializable` to handle that scenario (a redefinition of the `initialize` method inside an `inherited` macro, I think?), but looking through the file history I don’t see it, so I must’ve imagined it.

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 7, 2022, 11:55pm UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/8 "2022-05-07T23:55:22Z")

</div>

Wait, the thing I was apparently imagining actually works, though 🤯 Only difference here is the redefinition of `initialize` for the `JSON::PullParser`:

```crystal
require "json"

abstract class A
  include JSON::Serializable

  getter a1 : String?
  getter a2 : String?

  def initialize(*, __pull_for_json_serializable pull : ::JSON::PullParser)
    super
  end
  macro inherited
    def initialize(*, __pull_for_json_serializable pull : ::JSON::PullParser)
      super
    end
  end

  def initialize(*, @a1 = nil, @a2 = nil)
  end
end

class B < A
  getter b1 : String? = nil

  def initialize(*, @b1 = nil, **kwargs)
    super(**kwargs)
  end
end

pp B.new(
  a1: "a1",
  b1: "b1",
)

pp B.from_json({
  a1: "a1",
  b1: "b1",
}.to_json)

```

[carcin](https://play.crystal-lang.org/#/r/d560)

---

<div class="post-metadata">

**Author:** ![drhuffman12](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/drhuffman12/32/715_2.png) [@drhuffman12](https://forum.crystal-lang.org/u/drhuffman12)\
**Post date:** [May 8, 2022, 1:46am UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/9 "2022-05-08T01:46:02Z")

</div>

FYI, I commented out the `macro inherited .. end` part from that [Carcin](https://play.crystal-lang.org/#/r/d560), and it works:

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

---

<div class="post-metadata">

**Author:** ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)\
**Post date:** [May 8, 2022, 1:59am UTC](https://forum.crystal-lang.org/t/json-serializable-w-inheritance/4613/10 "2022-05-08T01:59:55Z")

</div>

Nice! This class hierarchy has a few layers so that _might_ be something that needs to stay, but I’m not sure.
