Overloading

Can I overload the constructor of a class? I have just tried to do so and crashed the IDE just by declaring the second method.

I don’t know about the crash, but you can absolutely overload the constructor of a class. It’s a common technique for the factory pattern (overriding, technically), among other things.

Yes you can… I use this all the time

BUT primary rule of OVERLOADING, the SIGNATURE MUST BE DIFFERENT

Constructor(a as integer)
Constructor(a as string)

is ok…
But two with same signature is not… it would confuse the compiler

Can you please elaborate? OS and Xojo versions and steps to reproduce?

Sorted it. In one declaration I had an argument

ParamArray items as variant

Instead of

ParamArray items() as variant

I thought a crash was a bit uncalled for though :wink: . Xojo 2014 r 2 on osx.

[quote=111392:@Mike Charlesworth]Sorted it. In one declaration I had an argument

ParamArray items as variant

Instead of

ParamArray items() as variant

I thought a crash was a bit uncalled for though :wink: . Xojo 2014 r 2 on osx.[/quote]
Well if you can give us steps on how to reproduce the crash we’ll fix it

[quote=111392:@Mike Charlesworth]Sorted it. In one declaration I had an argument

ParamArray items as variant

Instead of

ParamArray items() as variant
[/quote]
The parens are not required. There’s something strange here.

I can’t reproduce it myself, just tried again. Basically the steps I followed were:

Added a new class to the IDE
Added method constructor to the class with no arguments
Added method constructor to the class with arguments (ParamArray items as variant)
Clicked away from the arguments box in the inspector, mouse cursor changed to waiting/spinning colour wheel.
IDE crashed.

Xojo 2014 r 2 on osx.

But please fill a feedback case, so it’s not forgot.

Without steps that are reproducible it will likely just get closed as not reproducible

at least the crash report from OS X may help to get an idea where to lock at?

If there’s a crash report but without steps or a sample its going to be way down the priority list

Just dumping “stuff” into feedback is a way to make sure its clogged with unactionable “stuff”

Well, that might cause some confusion, since both constructors would be callable if no arguments are passed (i.e. it’s valid to have an empty paramarray).

That’s fine. It will work ok with empty paramarray

What I mean is: if you have the following:

class Whatever
sub Constructor()
sub Constructor(paramarray items as Variant)
end class

and you call

dim x as new Whatever()

Then which constructor is used? One (i.e. I) would think that the compiler should complain (“Don’t know which constructor to use”).

I would expect the mandatory signatures having priority over optionals, but seems it simply ignores the optional part and points out a conflict when finding something like:

sub xx( s as string) // 1
sub xx(s as string, optional n as integer, optional n1 as integer) // 2

Says the both conflict even if intended a completely different code for xx(“aaa”) and xx(“bbb”, 2)

It prefers that you make mandatory signatures.

I designed the algorithm, and my experience has been that defining rules for distinguishing between multiple legal interpretations of a single statement often leads to confusion. Newcomers to the language have to learn those rules, and everyone has to keep them in mind when reading through existing code. If you just have the compiler report an error instead, there are fewer things to memorize and fewer gotchas in understanding existing code.

The algorithm is therefore quite simple.

  • Collect all of the methods with the given name, in this case “xx”.
  • Eliminate any method which cannot be a legal option, because it has the wrong number of parameters or because its parameter types are incompatible with the argument values.
  • If there is exactly one method left, use it.
  • If there is exactly one method left whose parameter types exactly match the argument types, with no conversion required, use it.
    Otherwise, you get an ambiguous overloading error.

In this case, either of your methods ‘xx’ could be called without needing to convert a value, so neither method is clearly better. The fact that one method has more parameters than the other is not part of the algorithm.

I understand the decision. You know what could be great, return types in the signature due to things like this:

Function foo() As Integer // --sig-- name:(foo), params:(), return:(integer)
  Return 1
End Function

Function foo() As String // --sig-- name:(foo), params:(), return:(string)
  Return "One"
End Function

Sub Bar()

?  Dim i As Integer = foo()
  Dim s As String = foo()

  // Compiler says: There are several items with this name and it's not clear which one the call refers to

  // Well... To be true, in this case it could be (clear).  :P
 
End Sub

I know it would make the compiler a bit more complex interpreting contexts, but it would be great. Maybe in the future… :stuck_out_tongue:

It’s true, there are a good number of cases where overloading on the return type would be useful. It leads to some interesting complications, however - consider this:

[code]Sub Foo(x As String)
End Sub
Sub Foo(x As Integer)
End Sub

Function Bar() As String
Return “woot”
End Function
Function Bar() As Integer
Return 42
End Function

Foo(Bar())[/code]

This is a simple example, but let’s take it just one tiny step further:

Dim val As Variant = GoGetMyVariant() Foo(Bar() + val)

Now imagine the interactions with operator overloading, conversion operators, extension methods - it is clear that overloading on return type would allow you to construct arbitrarily complex statements in which it would be impossible to know the type or identify the implementation of any individual element without knowing the same about every other element.

I’m actually not worried about the compiler’s ability to untangle such knots; there are algorithms, it can crunch through them, CPUs are fast, and at the end it is either possible or not possible to identify a unique solution for the problem. But pity the poor human who has to read such code! Human beings are terrible at this kind of precise, step-by-step analysis of complex systems, which require you to hold many details in your working awareness at once. We inevitably forget things. The entire discipline of software development is built around finding ways to free us from keeping track of such details.

I decided to impose a simple universal rule: in xojo code, type information always flows from innermost to outermost, and never the reverse. The compiler evaluates the leaf expressions first, then the expressions which contain them, and so on; it pays absolutely no attention to the destination of the expression’s value while determining what the expression means. This does mean you have to write more verbose code when you have a situation which would call for return-type overloading, but at least it is easy to read and see what the code ultimately means.

I don’t claim that this is the only solution or that it is the best solution, and it is of course up to the developers in charge of Xojo today to take it into the future however they see fit, but this was the thinking I had when I built the algorithm we have today. I hope it is informative!

Sub Foo(x As String)
End Sub
Sub Foo(x As Integer)
End Sub

Function Bar() As String
  Return "woot"
End Function
Function Bar() As Integer
  Return 42
End Function

Foo(Bar())  //  extended precedence order? Math first, Strings after?

Foo(Bar()) // Compiler error signalizing needing disambiguation here using some kind of
            // selective operator like Foo(String(Bar())) ?