3

What's the reason why Crystal can't/won't resolve the type of this? (I see that the documentation does not mention that the compiler could infer instance method calls, but what's the rationale behind it, especially when only stdlib functions are involved? Compile time?)

class Something
  def blah
    @result = 1 + 1
  end
end


Something.new().blah

Compiler error:

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

error in line 3
Error: can't infer the type of instance variable '@result' of SomeObject

The type of a instance variable, if not declared explicitly with
`@result : Type`, is inferred from assignments to it across
the whole program.

The assignments must look like this:

  1. `@result = 1` (or other literals), inferred to the literal's type
  2. `@result = Type.new`, type is inferred to be Type
  3. `@result = Type.method`, where `method` has a return type
     annotation, type is inferred from it
  4. `@result = arg`, with 'arg' being a method argument with a
     type restriction 'Type', type is inferred to be Type
  5. `@result = arg`, with 'arg' being a method argument with a
     default value, type is inferred using rules 1, 2 and 3 from it
  6. `@result = uninitialized Type`, type is inferred to be Type
  7. `@result = LibSome.func`, and `LibSome` is a `lib`, type
     is inferred from that fun.
  8. `LibSome.func(out @result)`, and `LibSome` is a `lib`, type
     is inferred from that fun argument.

Other assignments have no effect on its type.

can't infer the type of instance variable '@result' of SomeObject

1 Answers1

3

If I'm not mistaken, Crystal used to be more aggressive in deducing the types. While it is elegant in certain examples, it creates more issues in bigger projects. Compilation times became a problem (incremental compilation is hard or impossible), and errors in the code (e.g. because of a typo) could be harder to track down when everything propagates.

In the end, keeping the interference rules simpler and falling back to explicit types for expressions was considered more practical. Here is a discussion about the change from 2015. I'm not involved in the language design, but reading through the thread, I think the arguments in the thread apply to your question (why 1 + 1 needs to be explicitly typed). Note that 1 + 1 is a simple case, but expressions can become arbitrary more complex once you allow them. In general, the compiler would have to work through the whole program code to do the analysis.

Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239