Method overloading

BlitzMax Forums/BlitzMax Programming/Method overloading

Brucey(Posted 2016) [#1]
Whilst I'm working on implementing it, what are peoples views on having Method overloading?

Here's a small example of overloading:
SuperStrict

Framework brl.standardio


Local rect:TRect = New TRect

Local draw:TDraw = New TDraw

draw.DrawRect(1, 2, 3, 4)
draw.DrawRect(rect)


Type TRect
	Field x:Int
	Field y:Int
	Field w:Int
	Field h:Int
End Type

Type TDraw

	Method DrawRect(x:Int, y:Int, w:Int, h:Int)
		Print "Drawing with x, y, w, h"
	End Method
	
	Method DrawRect(rect:TRect)
		Print "Drawing with rect"
	End Method

End Type

The above code would produce the following output:
Drawing with x, y, w, h
Drawing with rect


Normally in BlitzMax you would need to give a different name to one of the DrawRect() methods.
In some cases, you may end up with several methods with similar names performing the same functionality from different argument types.

With overloading, you can simplify your APIs.

Method overloading also opens up the potential to add operator overloading...


GW(Posted 2016) [#2]
Does this include constructors?
If there's no performance hit, i don't see it as a bad thing.
Although it will break Blide, I suppose its the price of progress.


Taron(Posted 2016) [#3]
OMG that would be fantastic! I'd be SUPER THRILLED!


Brucey(Posted 2016) [#4]
Does this include constructors?

I don't see why not.

Perhaps something along the lines of :

Local rect:TRect = New TRect(10, 10, 100, 100)

Type TRect
	Field x:Int
	Field y:Int
	Field w:Int
	Field h:Int

	Method New(x:Int, y:Int, w:Int, h:Int)
		Self.x = x
		Self.y = y
		Self.w = w
		Self.h = h
	End Method

End Type



Henri(Posted 2016) [#5]
At first I thought no, you can't have same method name in one type, but after doing some research I think why not. So it's cool.

EDIT: Of course it would give an error if there were 2 methods with a same name and same parameter types.

-Henri


H&K(Posted 2016) [#6]
@Henri

Re edit. Why?

Are you saying I can not override earlier methods?


Henri(Posted 2016) [#7]
Nope.

I'm saying this should not be allowed:
Type Test
	
	Method Do(this:Int)
		Print this
	EndMethod
	
	Method Do(that:Int)
		Print that
	EndMethod 

EndType


-Henri


Taron(Posted 2016) [#8]
Hahaha, that's pretty funny, Henri! xD
I would almost allow such a silly stuff to "compile", just to mess with the person, who wants it! xD

Jokes aside, Function overloading should be in there, too, for consistency's sake.
A complete dream come true would be operator overloading!
With my vector classes my life would be infinitely more enjoyable to have that!!! 8D


Dabhand(Posted 2016) [#9]
While your on Brucey, and I know its only marzipan, but:-

Type TRect
	Field x:Int
	Field y:Int
	
	
	Method Init(newX:Int,newY:Int)
		Self.x = newX
		Self.y = newY
	End Method
	
	'Overload + operator so we can add two types together
	Method Operator<+>:TRect(rect:TRect)
		Local tempRect:TRect = New TRect
		tempRect.x = Self.x + rect.x
		tempRect.y = Self.y + rect.y
		Return tempRect
	End Method
EndType

Local rect1:TRect = New TRect
rect1.Init(10,20)

Local rect2:TRect = New TRect
rect2.Init(100,200)

'Use the overloaded + operator for our types
Local rect3:TRect = rect1 + rect2

Print rect3.x 'Prints 110
Print rect3.y 'Prints 220


Cheers! :)

Dabz


Brucey(Posted 2016) [#10]
Method Operator<+>:TRect(rect:TRect)

Yeah, I'm not sure about the syntax for that yet.

But while we're on the topic, do you want to make a list of all the operators under consideration? ;-)


Dabhand(Posted 2016) [#11]
Well, arithmetic operators, modifying assignments operators(if pos)... I only generally use arithmetic ones and compound ones in C++, as I like the 'object = object + anotherObject' form of writing it over the more usual 'object = AddObjects(object, anotherObject)' setup!

Like I said, its marzipan really!

Dabz


Yasha(Posted 2016) [#12]
To voice an opinion way too late to make a difference, you should consider making operator polymorphism available before operator overloading. i.e.:
rect1 + rect2
' is identical to, and in fact just syntax sugar for:
rect1.__plus__(rect2)

...which would otherwise follow the existing runtime-polymorphic rules.

Special-casing operators to go straight to overloading will result in a multi-tier language design with muddy semantics. There's also very little practical value to demanding operators be static while methods be dynamic without also introducing templates (i.e. turning your language into C++). And nobody sane wants that.


Personally I don't think overloading is a good idea, mainly because I don't buy the reasoning that it does simplify an API to have the same name refer to multiple things without any control over this on the language side (there's no easy way for the compiler to enforce that the two DrawRect methods are semantically related, meaning you open up more error-surface by allowing overloading).

If you implement generics (true generics, don't waste your time with templates), you can completely replace overloading with Dictpassing anyway, allowing for all of the same advantages of shorter/clearer code (i.e. two methods both named DrawRect) without any overloading machinery or linguistic complexity. (In general, generics - parametric polymorphism - make a language simpler, while overloading - ad-hoc polymorphism - makes it massively more complex.)

Dictpassing works best with an "open" or "using" directive to allow easy access to scoped names. Given such a directive, a dictpassing version of BlitzMax could hypothetically look like this:

Notice that you trade off making your call externally explicit with the fact that a) both of the implementations of MultiplyAndAdd still get to use short names for operators that handle completely unrelated types; and b) a guarantee that all implementations of MultiplyAndAdd have exactly the same underlying structure (i.e. even though Int and Vec3 are unrelated and their +/* do different things, the enclosing function does the same thing in the context of what it means for that type).


Cocopino(Posted 2016) [#13]
First thought: great! Especially if this also implies the constructor/New Method.

But a concern of mine would be: will there be an IDE picking this up... I admit being spoiled by Visual Studio, but for me, it's too hard to go back to non IDE supported classes/methods.


seriouslee(Posted 2016) [#14]
I'd see it as a big plus! Brucey you just keep making Max better and better.


Derron(Posted 2016) [#15]
Henry:

I'm saying this should not be allowed:
Type Test
	
	Method Do(this:Int)
		Print this
	EndMethod
	
	Method Do(that:Int)
		Print that
	EndMethod 

EndType




How should the system know what kind of "Do()" you are using when passing an "int" ? Overloading needs to get different amount of params passed, or different types. What you are attempting could be done by using a different "Do()" in an extending type (a extends b).


bye
Ron


Cocopino(Posted 2016) [#16]

Type Test
Method Do(this:Int)
Print this
EndMethod

Method Do(that:Int)
Print that
EndMethod

EndType



No, that should indeed not be allowed. C# raises two helpful errors:
Error: Type 'Test' already defines a member called 'Do' with the same parameter types
Error : The call is ambiguous between the following methods or properties: 'Test.Do(int)' and 'Test.Do(int)'


AdamStrange(Posted 2016) [#17]
bruce. is this publicly testable ;)


Taron(Posted 2016) [#18]
Let the man do his thing, Adam! We don't want him to get boxed in while setting it all up! ;)


Brucey(Posted 2016) [#19]
is this publicly testable ?

There's a "bcc_overload" branch in github ( https://github.com/bmx-ng/bcc/tree/bcc_overload ) with the initial work committed, which currently clean-builds against the latest NG brl and pub modules.
Doesn't yet support function/New() overloading, but it should work enough for having a play with.

I'd suggest creating a new "BlitzMax area" for testing this, as it uses method name mangling which is incompatible with the current bcc (or of course you can simply swap between the new and old bcc's and rebuild everything each time).


AdamStrange(Posted 2016) [#20]
ok, no problem. I'll slowly get it all ready :)


Derron(Posted 2016) [#21]
ar: creating /BlitzMaxNG_overload/mod/brl.mod/blitz.mod/blitz.debug.linux.x86.a
Compile Error: Unable to find overload for bbgcvalidate(Int). Argument #1 is "Int" but declaration is "Byte Ptr". 
[/BlitzMaxNG_overload/mod/brl.mod/appstub.mod/debugger_mt.stdio.bmx;627;0]


(EDIT: removed second error, as it was a userbased error - aka based on my faults :-))


Sample I wanted to compile:


bye
Ron


Brucey(Posted 2016) [#22]
Your first error is fixed in github.
The other one I cannot reproduce, either with my local copy or a clean clone from the repo :-)

Your example outputs:
Constructing machine: Machine
Constructing terminator: Terminator


:o)


Derron(Posted 2016) [#23]
The other error was based on a borked bcc.conf (pointing to another BlitzMax installation) ...


Question: If I append the following to the sample above:
'should print: Constructing machine: Machine" ?
factory.Construct(TMachine(New TTerminator))

I pass the variable as "TMachine" - so should it still print "Terminator" (so use the "instance's type") or should it output "Machine" (use the "passed type")?



bye
Ron


Brucey(Posted 2016) [#24]
The cast to TMachine will cause it to choose Construct(obj:TMachine). It will print "Terminator" because the object is an instance of TTerminator.
Therefore the output in the third case would be :
Constructing machine: Terminator



Derron(Posted 2016) [#25]
Ok, so it chooses by the "given" type, not the "original" type.

Seems to do what it should. Let's see with what others come up.

PS: recognized that my question wasn't that correct at all: should have asked what "construct()" is called then. Glad you answered it already.



bye
Ron


Brucey(Posted 2016) [#26]
Here's an example of constructor overloading from the latest commit:
SuperStrict

Framework brl.standardio

Local b:TBase = New TBase
Print b.ToString()


b = New TBase(20)
Print b.ToString()

Local s:TSub = New TSub
Print s.ToString()

s = New TSub(60, 50, 10)
Print s.ToString()

Type TBase

	Field a:Int

	Method New()
		a = 99
		Print "~nTBase New()"
	End Method

	Method New(a:Int)
		Self.a = a
		Print "~nTBase New(int)"
	End Method

	Method ToString:String()
		Return "  TBase = " + a
	End Method
	
End Type


Type TSub Extends TBase

	Field b:Int
	Field c:Int

	Method New(a:Int, b:Int, c:Int)	
		Self.a = a
		Self.b = b
		Self.c = c
		Print "TSub New(int, int, int)"
	End Method

	Method ToString:String()
		Return "  TSub = " + a + ", " + b + ", " + c
	End Method
	
End Type

which outputs the following:
TBase New()
  TBase = 99

TBase New(int)
  TBase = 20

TBase New()
  TSub = 99, 0, 0

TBase New()
TSub New(int, int, int)
  TSub = 60, 50, 10


Still a ways to go, but testing is going well so far.


Derron(Posted 2016) [#27]
Without testing: How would "TSub" call the "New"-function of TBase. Is this even possible / intended?

I mean, when using "Method Init:TTypeName()" you are able to override this in an extended type and then call "super.Init()" to also handle the stuff done there.

possibilities:
Method New(a:int)
  super.New()
End Method

Method New(a:int)
  'parental "new" are already called - what happens to overloaded ones?
End Method



bye
Ron


grable(Posted 2016) [#28]
New() already calls its parents New() automatically.
This would simply be extended to overloaded New() as well, it would call its parents equivalent or default New() if none is defined.
This is how most other OO languages do it.

Another thing is if you want to allow calling a New() in the same type.
Type Base
  Method New()
    ' lots of work
  EndMethod

  Method New(x:Int)
    New()
    ' .. little work
  EndMethod
EndType

To follow the semantics of New() it would be required to be the first call in the method.


Derron(Posted 2016) [#29]
New() already calls its parents New() automatically.


So the question then is: which one is called?

a: New()
a: New(i:int, j:int = 0)
a: New(i:int)

b extends a
b: New(i:int)

With "b" wanting to take over the "initialization" of a, which "new()" is called then. And how to call a specific "super.New()" ?

Instead of "New()" (which does not state another scope than the "local" one) I would really prefer ("Super.New()") as "super" is already the keyword to access the parental class definition.



bye
Ron


grable(Posted 2016) [#30]
So the question then is: which one is called?
The one with the same prototype, just like with methods. Unless it hasent been overridden in which case vanilla New().

Yeah, if your gonna allow calling constructors of base classes, "Super.New()" is the only way really.

What i meant with my sample above is to call another constructor within the same type.
To limit the copy-pasta.


seriouslee(Posted 2016) [#31]
I agree with Derron. An extended class should have to explicitly call its parent constructor. Automatically calling a parents constructor could produce unwanted effects. Using Super.New(argument[s]) makes the most sense to me.


Derron(Posted 2016) [#32]
This would also allow to use other New()-variants then the one called for the extended type.

back to my sample:
Type B extends A
  Method New(i:int)
    Super.New(i, 2) 'calling New(i:int, j:int = 0) of a
    'do something else
  End Method
End Type


Still in question: how does the compiler know that New(i:int) is meant instead of New(i:int, j:int = 0) when calling Super.New(10).
Isn't this possible at all as the New(i,j=0) variant isn't 100% distinguishable?
-> for overloaded methods "default params" are not allowed - or are they?


bye
Ron


grable(Posted 2016) [#33]
Id rather not have to explicitly call Super.New() in every New().
Its already automatically called, why change the semantics? There is no ambiguity here.

Having the option of also calling Super.New() yourself is a good thing too, at which point the automatic calling is not done.

For default arguments, the same can be said of regular overloaded methods.
Pascal for example, treats this as an error.

If you are to allow such ambiguity, i would go with calling "New(x)" because of the number of arguments.
You gave it 1 argument, so you get the 1 argument version. Unless there only is the 2 argument version then that is what you get instead.


seriouslee(Posted 2016) [#34]
Grable:
After re-analyzing Brucey's example I see what you are referring to. I had it my head a New method with parameters passed to it (Example: New(int, float, int)) in which I would want to have to explicitly call from an extended object, but, yes, a default New constructor (without parameters) should automatically be called.

In short, I'm with you :)


Derron(Posted 2016) [#35]
On the one hand:
Do not do "default New()" is called "parametrized New()" is not called.
This leads to "is super.new() called now?" thoughts which means: ambiguity.


On the other hand:
If "New(params)"-definition is the same for base and extended type, then the "super.New(params)" should be called - at least is this what I would expect to happen (because of "super.new()" being called implicitely in vanilla BMX) .
But: vanilla BMX does not contain overload, so expectations to how things behave are non-existent. As I expect "MyMethod(int)" to not call "Super.MyMethod(int)" on its own, I am not sure why I should expect "New()" to behave similar.
All in all even in vanilla this isn't consequently done then.


How do other languages tackle it?

bye
Ron


grable(Posted 2016) [#36]
@seriouslee
hehe, dont worry. Its all up to Brucey in the end anyway ;)

Id also like to know the semantics of the below:
Type A
  Method New( x:Int)
EndType

Type B Extends A
  Method New( x:Int, y:Int)
EndType

Local t:A = New A    ' allowed?
Local b:B = New B(1) ' allowed?



Brucey(Posted 2016) [#37]
Id also like to know the semantics of the below

t calls the default constructor for A
b calls the overloaded constructor for A

which is what you'd expect, I think?


Brucey(Posted 2016) [#38]
vanilla BMX does not contain overload, so expectations to how things behave are non-existent

Only if you've never used other programming languages, I suppose?


Brucey(Posted 2016) [#39]
a: New(i:int, j:int = 0)
a: New(i:int)

Probably not a good idea, since you would not be able to call New a(i).
I suppose that could be considered applicable for a compilation error - since you are introducing ambiguity within a single type.

On the other hand,
a: New(i:int, j:int = 0)
b: New(i:int)

is fine, as the scope separates ambiguity here.
If you call new b(i), it will call b's constructor - since the scope takes precedence.


Brucey(Posted 2016) [#40]
I hadn't considered constructor chaining... I suppose it is a reasonable thing to implement, as with Super.New() calling, all of which would need to be done as the first statement.

I'll look into that.

It gets somewhat complicated, I see ;-)


Derron(Posted 2016) [#41]
Only if you've never used other programming languages, I suppose?


So BMX-NG is only for people being used to other programming languages?

When it comes to "oop" I never really used overloading (only a bit tinkering in java, but I avoided such "odd situations" - and "overloaded constructors").


What I wanted to express in the prior posts is: there should be some "rules" a coder could follow. "Method New()" is already breaking it (you would better have named it "__construct" or so - to _not_ name it like the keyword.

keyword type
new bla -> (new instance of bla).__construct()
delete bla -> bla.__delete()

Because now it seems as if methods could be called that way ("methodname type"). Of course this inconsistency is not your (bmx-ng's) fault but blitzmax'.


Again: do not set your expectations to be "what all others expect" - there is a reason to have me and other "amateurs" on your side: we tell what we expect, without the "genious knowledge" some of the more experienced coders have.
But also do not get that wrong, it is your decision how things will evolve or not. We are surely able to bend our minds accordingly until we get used to it.
Just want to "brainstorm" a bit while things are not settled yet.


bye
Ron


grable(Posted 2016) [#42]
which is what you'd expect, I think?
Yeah, i expected as much on account of bmx default constructors (even if they are empty :p).
Though there are languages that do not have default constructors (like Pascal and C++) in which an object must use one of the defined ones.

I dont know which is better really. Objects in blitzmax always have zeroed out data, so they are technically initialized even without a constructor.
So not requiring to call a constructor does fit with prior conventions in regards to constructor functions/methods doing the initializing in vanilla bmx.
The only difference would be that you cant initialize an already created instance, unless calling New() on them would be allowed ;)


Derron(Posted 2016) [#43]
Objects in blitzmax always have zeroed out data


They contain the "null"-equivalents. so
int = 0
string = ""
object = null

For me this means, they are _not_ initialized.
Exception is if your type already predefines things:

type test
  field listA:TList = CreateList() ' not null on "new test"
  field listB:TList                ' null on "new test"
end type


bye
Ron


grable(Posted 2016) [#44]
I guess it depends on where your coming from. In C initialized==0 or any other valid pointer/data, as everything not explicitly initialized is random garbage.
Which is why i used "technically" ;) The main point is that they are in a defined state.

Still, whether to allow default constructors when there are other defined ones is a hard one. As doing so might be seen to create uninitialized objects with no hope of ever being initialized to the proper state.
Stay with convention or go for more correctness? :p


Derron(Posted 2016) [#45]
Got and understood that point about null/initialized.
(albeit I am not sure but think to remember that I also had "garbage" values in some field-properties - years ago - maybe that was changed some versions ago or so?)


@ New
Wouldn't it be easier to disallow that feature at all (if we would not come to a consense :-)) there is still "new bla.init()" (which could be overloaded without trouble then).
But like said: we will get used to whatever you will come up.

Of course "SendMessage()" and other built-in methods should be overloadable like normal methods.


bye
Ron


Brucey(Posted 2016) [#46]
In BlitzMax, all fields are initialised to *something*, either their default "zero" state, or whatever was specified in the field declaration.

@ New

Well, GW wanted it, so I thought I may as well implement it :-p
The general direction I'm taking with the overloading is to work in a similar way to Java, whose rules are basic and fairly easy to implement - but of course, in the flavour of BlitzMax.

Whether or not I can get it right, is another matter entirely :-)


GW(Posted 2016) [#47]
Overloaded constructors is the probably the only kind I would use. If it gets into swampy territory, then don't add it on my account. Backwards compatibility is what would effect me the most in my projects.


Cocopino(Posted 2016) [#48]

Backwards compatibility is what would effect me the most in my projects.



I also think this should be one of the most important factors, even for new users not having to port any code (code archives etc.)


Derron(Posted 2016) [#49]
If you did not use overloading in your current projects (chances are high if you use vanilla BMX ...) backwards compatibility should be no issue.

Once you use overloading then, it of course wont work with vanilla BMX any longer. (If you wrote it in a way, vanilla ignored the new "functionality", at least your application logic would be broken).


bye
Ron


Cocopino(Posted 2016) [#50]

If you did not use overloading in your current projects (chances are high if you use vanilla BMX ...) backwards compatibility should be no issue.



Well, it does once we start renaming New() to __construct() or similar changes...
And while I've grown fond of using PHP over the years, naming conventions should probably be copied from elsewhere ;)


Brucey(Posted 2016) [#51]
The name New() isn't changing.


Brucey(Posted 2016) [#52]
Here's a small contrived example which shows constructor chaining :
SuperStrict

Framework brl.standardio

Local s:TSub = New TSub(15)
Print s.i

Type TBase

	Field i:Int

	Method New()
		New(10)
		Print "TBase() : " + Self.i
	End Method
	
	Method New(i:Int)
		Print "TBase(int) : " + Self.i
		Self.i = i
	End Method

End Type


Type TSub Extends TBase

	Method New()
		Print "TSub()"
	End Method
	
	Method New(i:Int)
		Print "TSub(int) : " + Self.i
		Self.i = i
	End Method

End Type

which outputs the following:
TBase(int) : 0
TBase() : 10
TSub(int) : 10
15

And now a description of what occurred :-)

Initially, TSub.New(i:Int) is called.
Since it doesn't call another constructor itself, the default is to call the Super type default constructor.
So, TBase.New() is called next.
This in turn calls TBase.New(i:Int).
Finally, the Object default constructor is called.

:o)


seriouslee(Posted 2016) [#53]
Thanks for the info, Brucey. Question: Is New() required? Would the following be acceptable?
Local a:TType = New TType(15)

Type TType
  Field value:int

  Method New(newValue:int)
    value = newValue
  End Method
End Type



Henri(Posted 2016) [#54]
Hi,

your example contains New() ?

EDIT: Oh, I thought you meant omitting New() totally.

-Henri


Brucey(Posted 2016) [#55]
Is New() required?

No. You don't need to override the default New constructor.

In your example, you can still call "New TType" to create a new instance of TType...
SuperStrict

Framework brl.standardio

Local a:TType = New TType(15)
Print a.value

a = New TType
Print a.value

Type TType
  Field value:int

  Method New(newValue:int)
    value = newValue
  End Method
End Type

.. would output :
15
0



Derron(Posted 2016) [#56]
Since it doesn't call another constructor itself, the default is to call the Super type default constructor.


So if adding a "New()" to the overloaded New(int) of TSub would then call this instead of "Super.New()" ?

Also: "super.New()" is always called - except there is no parent?
So for a "base class" all "New(...)"-variants wont call New() too?


Edit: feel free to update the github repo - so I could answer above's questions on my own.

bye
Ron


Brucey(Posted 2016) [#57]
So if adding a "New()" to the overloaded New(int) of TSub would then call this instead of "Super.New()" ?

If your code looks like this :
Type TSub Extends TBase
	Method New(i:Int)
		New()
		Print "TSub(int) : " + Self.i
		Self.i = i
	End Method
End Type

It would call New() in TBase (either the default or the overridden one). There is *always* at least a default New().

If your code looks like this :
Type TSub Extends TBase
	Method New()
		Print "TSub() : " + Self.i
	End Method

	Method New(i:Int)
		New()
		Print "TSub(int) : " + Self.i
		Self.i = i
	End Method
End Type

calling New TSub(10) would result in a call to TSub New().


Derron(Posted 2016) [#58]
Tried the newest revision - works nicely.




outputs:
TBase.New()
----
TBase.New(i:int)
----
TBase.New()
TSub.New()
----
TBase.New(i:int)
TSub.New(i:int)
----
TBase.New()
TOtherSub.New()
----
TBase.New()
TOtherSub.New(i:int)
----


So what is happening:
- if you extend a type the New-Methods will call the parental New()-method
- they call the non-overloaded-New()-method (without params)
- if you call a custom "Super.New(xyz)"-method, the default Super.New() is skipped

Is this the "expected" behaviour? or should it try to call the same overloaded New(xyz)-method of its parent (if available) instead?

In this case this should mean, that the last output lines would look like this:
TBase.New(i:int) '<---- with param now
TOtherSub.New(i:int)



Like said: I think I would go d'accord with both solutions, just asking what is "expected" there (by the other Blitzmax-users - interested in NG).


bye
Ron


Brucey(Posted 2016) [#59]
Is this the "expected" behaviour?

Yes. Whenever you don't specifically call a Super constructor in New() it automatically calls the default super constructor (i.e. the one with no parameters). This is also what happens with the legacy compiler.


Brucey(Posted 2016) [#60]
Here's an example of a simple copy constructor :
SuperStrict

Framework brl.standardio

Local rect:TRect = New TRect(10, 10, 100, 200)
Print rect.ToString()

Local r2:TRect = New TRect(rect)
Print rect.ToString()

Type TRect

	Field x:Int
	Field y:Int
	Field w:Int
	Field h:Int

	Method New(x:Int, y:Int, w:Int, h:Int)
		Self.x = x
		Self.y = y
		Self.w = w
		Self.h = h
	End Method
	
	Method New(rect:TRect) ' copy constructor ;-)
		New(rect.x, rect.y, rect.w, rect.h)
	End Method

	Method ToString:String()
		Return x + ", " + y + ", " + w + ", " + h
	End Method
	
End Type

:o)


Derron(Posted 2016) [#61]
This is also what happens with the legacy compiler.


This is a matter of interpretation.

For _me_ it calls the super.method of the one I am in at this moment.
So when in new(int) it should call super.new(int).

Your interpretation is: when you create a new object in vanilla bmx ...all new() methods "downwards" are getting called.

As new(int) is an equal creator to new() i do not see the need to make new() a preferred method. Backwards compatibility isn't given in both scenarios.


But like said..just a personal thought ... no need to adjust the behaviour if I am alone with that :-)


bye
Ron


Brucey(Posted 2016) [#62]
So far, the following appears to be working :

* Method overloading.
* Function/static overloading (in types).
* Constructor (New) overloading.
* ToString, Compare and SendMessage overloading.

which probably covers most things.

The system uses name mangling when generating source. You can optionally disable mangling of Functions using { nomangle } metadata - useful for publicly accessed type functions (often used when calling into BlitzMax from C/C++).


GW(Posted 2016) [#63]
Cool!
Will this be merged into the main branch?


Brucey(Posted 2016) [#64]
Yes, at some point.

I'm tidying up my modules in the meantime, applying nomangle where appropriate - which "generally" is all that needs to be done. There are the occasional edge cases where a method argument will need to be specifically cast to a type. For example, if you are passing a Double arg into a Float param you will need to manually cast it down to Float, or you will get a compilation error which should tell you that you can't pass a Double into a Float.

Here's an example of what I mean :
SuperStrict

Framework brl.standardio

Local t:TType = New TType

Local a:Int = 10
Local b:Int = 5
Print t.add(a, b) ' ok. widens int to float

Local c:Float = 6.8
Local d:Float = 9.1
Print t.add(c, d) ' ok. args match param types

Local e:Double = 20
Local f:Double = 6
'Print t.add(e, f) ' compile error. Cannot narrow double to float.
Print t.add(Float(e), Float(f)) ' ok. cast down to float.

Type TType

	Method add:Float(a:Float, b:Float)
		Return a + b
	End Method

End Type