What about a syntax sugar for hash declaration? 🔥

Instead initialize a hash with type restriction this way:

class Foo
  @data : Hash(String, Hash(String, Value)) = {} of String => Hash(String, Value)
end

also accept this shorter version:

class Foo
  @data : Hash(String, Hash(String, Value)) = {}
end

The rule seems simple, if the right hand of the assign operator has a hash type restriction, let the hash be of that type.

Some would argue to write as the code bellow

class Foo
  @data = {} of String => Hash(String, Value)
end

But this doesn’t put the type restriction in the attribute, so some code later can do @data = 2 and it would change the @data type.

2 Likes

Related: Autodetect types of empty array/hash/splat arguments properly · Issue #9774 · crystal-lang/crystal · GitHub

1 Like

From issue comments

The empty [] can probably be allowed. The {} won’t happen as it is ambiguous with the empty tuple and the empty block.

Maybe {} of * instead of just {}? :grimacing:

Or: {=>} :grimacing:

1 Like

I feel like this could be worked around because it’s impossible to have an empty tuple (in normal code anyway) and braces wrapped in parentheses and not prefixed with an identifier would explicitly indicate the value is a hash and not a block, i.e.

def foo(value : Hash(String, String)) : Nil
end

def bar(& -> _) : Nil
end

foo {} # invalid, parsed as a block
foo(bar {}) # invalid, parsed as a call to `bar`
foo({}) # valid, cannot be parsed as any other expression

The same can be said for initialization with the same rules:

class Foo
  @bar : Hash(String, Int32) = {} # still valid

  def initialize(@bar = {}) # also valid
  end
end