#2925 Newb interpretation of type inference with empty arrays

Gary Wed 24 Jul

I thought this little experiment might help others learning Fantom's type inference. This is what I've come up through experimentation:

msgs := ["Gary", "Gerry", "Kathy"]
echo(Type.of(msgs))   // inferred as sys::Str[]

msgs0 := [,]
echo(Type.of(msgs0)   // inferred as sys::Obj?[]

Str[] msgs1 := [,]    // with LHS type annotation - no effect
echo(Type.of(msgs1))  // inferred as sys::Obj?[]

msgs2 := Str[,]        // with RHS type annotation
echo(Type.of(msgs2))   // inferred as sys::Str[]
  1. Fantom will infer the array data type if initialized during declaration.
  2. LHS type annotation appears to have no effect on an empty array and will be inferred as sys::Obj?[] type.
  3. RHS type annotation of an empty array will be inferred by the type annotation.

Here's Claude3's interpretation of the above:

Your experimentation and observations about Fantom's type inference for arrays are quite interesting and mostly correct. Let's break down your findings and add some clarifications:

  1. msgs := ["Gary", "Gerry", "Kathy"] This is correct. Fantom infers the type as Str[] because all elements are strings.
  2. msgs0 := [,] Correct. An empty list without type annotation is inferred as Obj?[].
  3. Str[] msgs1 := [,] Your observation is partially correct, but there's a subtle difference. The LHS type annotation does have an effect, but it's not visible when you use Type.of(). The variable msgs1 is actually of type Str[], but its runtime type (which is what Type.of() returns) is still Obj?[]. This is because Fantom uses erasure for generics, similar to Java.
  4. msgs2 := Str[,] Correct. When you provide a type annotation on the RHS for an empty list, Fantom uses that type.

Your conclusion is mostly accurate, but let's refine it a bit:

  1. Fantom will infer the array data type if initialized with non-empty elements during declaration.
  2. An empty array without type annotation will be inferred as Obj?[].
  3. LHS type annotation for an empty array does affect the compile-time type, but the runtime type (as reported by Type.of()) will still be Obj?[] due to type erasure.
  4. RHS type annotation of an empty array will be used for both compile-time and runtime type inference.

To further illustrate point 3, you could try this:

Str[] msgs1 := [,]
msgs1.add("Hello")  // This will compile fine
msgs1.add(42)       // This will cause a compile-time error

This shows that the LHS type annotation is respected by the compiler, even though Type.of() doesn't reflect it due to type erasure.

Your experiment is indeed helpful for understanding Fantom's type inference system, especially for newcomers to the language. It highlights some of the nuances in how Fantom handles type inference and erasure for collections.

Erasure for Generics

Certainly, I'd be happy to explain the concept of "erasure for generics."

Type erasure is a process used in some programming languages, including Java and Fantom, where the compiler removes all information related to generic types during compilation. This means that at runtime, the generic type information is "erased" and not available.

Here's a breakdown of what this means:

  1. Compile-time vs. Runtime:
    • At compile-time, the compiler knows about the generic types and uses this information for type checking.
    • At runtime, this generic type information is no longer available.
  2. Why it's done:
    • It allows for backward compatibility with older versions of the language that didn't support generics.
    • It can lead to more efficient code, as there's no need to carry type information at runtime.
  3. Consequences:
    • You can't do certain operations at runtime that depend on knowing the exact generic type.
    • Methods like Type.of() in Fantom will return the erased type, not the generic type.
  4. Example in Fantom: When you declare Str[] msgs1 := [,], the compiler knows it's a Str[]. But at runtime, it's treated as Obj?[].
  5. Practical implications:
    • The compiler will prevent you from adding non-String elements to msgs1.
    • But runtime type checks will see it as an array that can hold any object.

This is why in your experiment, Type.of(msgs1) returns Obj?[] even though you declared it as Str[]. The generic type information (Str) has been erased at runtime.

Understanding type erasure is important when working with generics, especially when doing runtime type checks or reflection-based operations.

Let me know if there are any concerns or corrections! :)

Login or Signup to reply.