This defines a function that returns a string. and .to_json returns a string.
But, this does not put any constraints no @bar. anything that has a .to_json could be in @bar.
The first example is an example of duck typing. I.e. the compiler figures out all invocations of #foo and knows that each value passed to it responds to .to_json.
However the 2nd example is introducing an instance variable which needs to be typed and known ahead of time. I.e. there’s not really a way the compiler can type this, as the error says because it doesn’t comply with the inference rules.
To expand on the previous comments: Technically, the compiler could figure out that the call to Foo.new receives a Hash and thus type the instance variable accordingly.
In fact, this used to work in earlier iterations of the language. But it was later changed, because it involved too much magic to be sane (that’s my interpretation at least; I wasn’t around at that time, though).
Now type instance variables require a type restrictions. In many simple cases, the type can be inferred from the variable assignment (for example, when the value is a literal).
Could you show us some more code and what you are trying to achieve? Talking about these things in isolation sometimes isn’t good. There might be a better way to do what you want.