#2696 Lost type with it-block

dubek Sat 12 May 2018

I'm new to Fantom, so excuse me if this report is just a misunderstanding.

I found that using an it-block with map loses the type of the new returned collection (List or Map). For example:

fansh> a := [1,2,3]
[1, 2, 3]
fansh> a.typeof
sys::Int[]
fansh> b := a.map { it }
[1, 2, 3]
fansh> b.typeof
sys::Obj?[]
fansh> a == b
false

The same happens with Maps:

fansh> h := ["a": "b", "c": "d"]
[a:b, c:d]
fansh> h.typeof
[sys::Str:sys::Str]
fansh> h2 := h.map { it + "X" }
[a:bX, c:dX]
fansh> h2.typeof
[sys::Str:sys::Obj?]

Using a full closure (instead of the it-block) solves the issue:

fansh> [1,2,3].map { it }.typeof
sys::Obj?[]
fansh> [1,2,3].map |Int x -> Int| { return x }.typeof
sys::Int[]

Another thing is that the compiler happily allowed me to pass such a sys::Obj?[] variable to function which takes an Int[] parameter:

class Main
{
  static Void work(Int[] nums)
  {
    echo(nums.toCode)
    nums.each { echo(it) }
  }

  static Void main()
  {
    a := [1,2,3]
    work(a)
    b := a.map { it * 10 }
    work(b)
  }
}

Running this gives:

sys::Int[1, 2, 3]
1
2
3
sys::Obj?[10, 20, 30]
10
20
30

Where I'd expect the nums argument to always be Int[] (or maybe a List of objects that inherit from Int), or the compiler should complain about type mismatch on work(b).

brian Sat 12 May 2018

Hi dubek, welcome to Fantom!

Typically with map you are creating a new list (or map) of a different type. The runtime will type the result based on your closure's return type:

fansh> [1, 2, 3].map |x->Str| { x.toStr }.typeof
sys::Str[]

Another thing is that the compiler happily allowed me to pass such a sys::Obj?[] variable to function which takes an Int[] parameter

Unlike Java or more classical statically typed languages, Fantom only makes it a compile time error when it knows for sure that the type is wrong. If the type could be right, but would require a cast in Java or C# then the compiler will allow it and use an implicit casting. See docLang::TypeSystem#implicitCasts for more details. In general we find this to be a very pragmatic approach for the type system

SlimerDude Sun 13 May 2018

-- deleted --

SlimerDude Sun 13 May 2018

Hi Dubek,

I'm reading 2 queries in your post:

1). Type info lost from it-blocks

Yes, the return type is lost from it-blocks / implicit functions.

This is a limitation of the compiler, for it can not truly know (in every situation) what is being returned until runtime. Because of this, it simply defaults to Obj?.

Agreed, for simple statements the compiler could be a bit cleverer. But as you stated, it can be worked around by fully qualifing the function parameters.

Note there are a couple of other forum posts related to this:

2). The un-strict compiler

Yes, the Fantom compiler is a bit looser than compilers for other statically typed languages and this is one of the areas where Fantom excels.

As far as the compilier is concerned, if something could work then it assumes it does work!

It extends some trust to the programmer and prevents you from having to down cast everywhere - it really cuts down on the amount of code you have to write.

I give an example and say more here: http://www.alienfactory.co.uk/articles/fantom-the-developers-choice#typeInference

I hope this helps, and let us know how you're getting on with that Fantom Lisp implementation!

Steve.

dubek Mon 4 Jun 2018

Just an update: the Mal (Make-a-Lisp) implementation is done and merged! The code is at https://github.com/kanaka/mal/tree/master/fantom .

Login or Signup to reply.