New Self

BlitzMax Forums/Brucey's Modules/New Self

Yasha(Posted 2016) [#1]
BlitzMax NG doesn't seem to like this pattern, which is supported in BlitzMax BRL:

Type MyException
	Function Make:MyException(code:Int, extra:Object = Null)
		Local e:MyException = New Self    ' <--- Syntax error: expecting identifier
		e._code = code ; e._extra = extra
		Return e
	End Function
	
	Function Raise(code:Int, extra:Object = Null)
		Throw Self.Make(code, extra)    ' <--- Illegal use of Self within static scope
	End Function
End Type


It's not an accidental feature; BlitzMax BRL supports Self for types in the logically-expected contexts and gives clear error messages (referring to the fact that they're not Objects) if you misuse them, so it was definitely designed this way.

Can this be implemented? (For that matter, is reaching 1:1 with BlitzMax BRL on minor issues like this considered a goal, or a nuisance?) I notice that the second message also indicates that NG has consciously made a decision on this matter, but it's a different one from BRL. Correcting a perceived bug, or simply an independent design choice?

I use this a lot; it seems like better style than explicit repetition. Good if it's long, too.


Brucey(Posted 2016) [#2]
Can this be implemented?

Sure :-)

Would you like to open an issue? ( https://github.com/bmx-ng/bcc/issues )


Yasha(Posted 2016) [#3]
Thanks! Opened.


Derron(Posted 2016) [#4]
Aside the bug: nice idea, really saves typing long typenames. A pity this does not work for return types (method get:self()) - would save some writing when else having to override methods just to return the extended type instead of the original one.

Current

Type TBaseClass
  Field x:int
End Type

Type TExtendedClass extends TBaseClass
  Field extendedProperty:int
End Type


Type TBaseClassCollection
  global instance:TBaseClassCollection
  Function GetInstance:TClassCollection()
     return instance
  End Function

  Method GetChild:TBaseClass(guid:string); ...;Return child; End Method
End Type

Type TClassCollection extends TBaseClassCollection
  Function GetInstance:TClassCollection()
     'handle potentially needed collection conversion from base collection
     ...
     return TClassCollection(instance)
  End Function
 
  Method GetChild:TExtendedClass(guid:string); ...;Return TExtendedClass(Super.GetChild(guid); End Method
End Type


I use similar constructs for various collections (as vanilla does not allow interfaces - and I need to avoid cyclic dependencies - which enforces me to have base classes to refer to, and implementations/extended classes to specialice behaviour). Without overriding "GetChild" you will have to "cast-verify-type" on your own, also this allows chaining:

TBaseClassCollection.GetInstance().GetChild("bla").x
TClassCollection.GetInstance().GetChild("bla").extendedProperty



@Yasha
Is there some simple way to simplify above's approach? Something similar to the "new self" 'secret' I do not know?


bye
Ron


Yasha(Posted 2016) [#5]
Not one I can think of, sorry.

To be honest I tend to do the opposite, work a lot with Object and Invoke. My own de-facto solution regarding interfaces in the BRL compiler (not currently using my own Interface patch in production, perhaps I should) is to do something like:

Type IFooBar Final
    Function Foo(_self:Object)
        Local _foo:TMethod = TTypeId.ForObject(_self).FindMethod("Foo")
        If _foo Then _foo.Invoke(_self, Null)
    End Function
    Function Bar:Int(_self:Object, x:Int)
        Local _bar:TMethod = TTypeId.ForObject(_self).FindMethod("Bar")
        If _bar Then Return Int(String(_bar.Invoke(_self, [Object(String(_self))])))
    End Function
End Type

Function Implements:Int(o:Object, i:String)
    Local t:TTypeId = TTypeId.ForName(i)
    If t.ExtendsType(ct) Then Return True
    While t <> ObjectTypeId
        If t.Metadata(i) Then Return True
        t = t.SuperType()
    Wend
    Return False
End Function

Type A { IFooBar }
    Method Foo()
        Print "A foo"
    End Method
    Method Bar:Int(x:Int)
        Print "A bar received " + x
    End Method
End Type

IFooBar.Foo(New A)

...etc.

It's not very formally codified actually. Lucky thing performance isn't an issue for my code.


Derron(Posted 2016) [#6]
While this is surely not the worst approach, I think there must exist something "easier" (the invokation is a bit ... hmm... hard to read).
Using Reflection might be a bit "heavy" (albeit I do not know the impact but loosely remember, that there was some talk about it, when Mark introduced it to BlitzMax).


Once NG is doing all I need (read: works and the modules compile fine :-) it might be a good chance to cut loose ends and to switch things to use "interfaces" (which Brucey nicely implemented in NG already)...


Feel free to come up with other ideas :-)


bye
Ron


Yasha(Posted 2016) [#7]
Thanks for changing this. (Took me an embarrassingly long time to work out that the fix was applied to a different branch.)

Now more of my project compiles, I have more incompatibilities to report... which I'm sure is delightful news. I'll do that over at the issues list.