JSON::Serializable on optional array becomes nil. Why not []. Impossible to tier on nil

Hej!

I’m new to this pleasent crystal. And also unfamiliary with usage on most bells and whistles here, but…

I got stuck when parsing JSON.

There are optional fields in the input. No problems with basic types.

But optional on Array becomes Nil if not present. I would like to get an empty array instead.

Example

class ARecursive
    include JSON::Serializable
    ...
    property kind : String
    property someopt : String?
    ...
    property deeper : Array(ARecursive)?
    ...
end

I parse the input like

thejson = ARecursive.from_json(File.read(somefilename))

But I can’t iter on this as deeper is declared as

(Array(ARecursive) | Nil) by JSON::Serializable

This iteration will not compile

thejson.deeper.each {|d|d}
Error: undefined method 'each' for Nil (compile-time type is (Array(ARecursive) | Nil))

What to do? Is it possible to iter on such a type using some smart pattern? Or are there any other set up on JSON::Serializable?

The recursive is not the problem. (I think?)

Thank’s
Willy

The simplist way to fix this is just give that property a default value. E.g.

property deeper : Array(ARecursive) = [] of ARecursive

Then if it’s not supplied in the JSON, it’ll use that, otherwise what’s in the JSON.

2 Likes

Thank’s a lot. The power of you and crystal shows up.

willy

1 Like

Alternatively, you could also accept the Nil type and add a guard for that when you want to iterate:

if deeper = thejson.deeper
  deeper.each {|d|d}
end
# or (shorter):
thejson.deeper.try &.each {|d|d}

I will try that too; for learning at least.

Thank you for your friendly support

/willy