fantom

Accessing Fantom class' members from a member function in a constructor it-block?


If I define this Fantom class

const class Mixed
{
  const Int whole
  const Int numerator
  const Int denominator

  const | -> Int[]| convertToFrac

  new make( |This| func ) { func( this ) }
}

And I want to create an instance defining the convertToFrac function, like this:

class Example
{
  Void main( Str args )
  {
    mixed := Mixed {
      whole = 2
      numerator = 3
      denominator = 8
      convertToFrac = |->Int[]| {
        return [ whole * denominator + numerator, denominator ]
      }
    }
  }
}

The compiler complains saying:

Is there any way to refer to the object "mixed" being created from within the function "convertToFrac", also being defined, without passing the "mixed" object as a parameter of the function?

If I prepend each variable with "mixed", like so:

return [ mixed.whole * mixed.denominator + mixed.numerator, mixed.denominator ]

The compiler complains: Unknown variable 'mixed'.

Using this.whole doesn't make sense as it refers to the Example class. Using it.whole doesn't make sense either as it refers to the Function.

Can anyone please suggest the way to access the "mixed" object from within the "convertToFrac" function?


Solution

  • As you correctly assessed, the issue is that you're using an it-block inside an it-block, and because you're using an implicit it (i.e. you're don't have any it qualifiers) there is confusion as to what's being referenced.

    I'll write out the it qualifiers out long hand so you can see what's going on:

    mixed := Mixed {
        // 'it' is the Mixed instance
        it.whole = 2
        it.numerator = 3
        it.denominator = 8
    
        it.convertToFrac = |->Int[]| {
            // 'it' is now the func param
    
            // 'it.whole' doesn't exist, because there is no func param
            return [ it.whole * it.denominator + it.numerator, it.denominator ]
        }
    }
    

    Your idea of using the mixed variable qualifier was a good one but, unfortunately, whilst processing the ctor the mixed variable hasn't been created yet so can't be referenced.

    But you can create your own mixed variable in the it-block, and the following compiles and runs quite happily:

    mixed := Mixed {
        // 'mixed' doesn't exist here yet, because we're still creating a value to assign to it
        it.whole = 2
        it.numerator = 3
        it.denominator = 8
    
        // assign `it` to our own `mixed` variable
        mixed := it
        it.convertToFrac = |->Int[]| {
            // use our own `mixed` variable
            return [ mixed.whole * mixed.denominator + mixed.numerator, mixed.denominator ]
        }
    }