Given this mapped type declaration (compiling on ECHOES):
Foo = public class mapped to System.Random
end;
I can then instantiate using any of the constructors supported by the System.Random class even though I have not mapped any constructors:
var f1 := new Foo; // seeds with 'timer'
var f2 := new Foo(100); // seeds explicitly with 100
But this then fails (does not compile):
var i := f1.Next(100) + 1; // ERR: No such member
The mapped type appears to be endowed with all of the constructors of the type that is mapped to. However, the resulting instance has only the methods of a System.Object (since we’re on ECHOES in this case). It does not provide any of the methods of System.Random unless I then explicitly map them:
Foo = public class mapped to System.Random
method Next(limit: Integer): Integer; mapped to Next(limit);
end;
The absence of instance methods makes sense. If all methods were automatically mapped this would “pollute” the interface of that class on each platform.
But it seem a little surprising then that the constructors are automatically mapped. I might expect the default/parameterless constructor to be auto-mapped although even that may be questionable given that the existence of parameterless constructor on all underlying mapped types does not necessarily imply that those constructors will result in the same initialised state of an instance. If that makes sense.
So my question is…
Is this behaviour w.r.t constructors on mapped types “by design” and something that can/should be relied on, or should we explicitly map constructors when mapping types as we seem required to do for any other methods ?
ASIDE: Also a minor bug I think. This does not compile:
Foo = public class mapped to System.Random;
Yields “semi-colon required” error and even an auto-fixit which adds another semi-colon. Hence the “empty” declaration with an “end;” in my example above. “Empty” mapped type declarations might not make sense but this error that results is a bit odd.
I wonder if it would not also be possible to suppress the platform members that are present.
i.e on ECHOES my f1/f2 instances have a GetHashCode() method etc. Since this is a mapped type, having any platform specifics in there is likely to be a mistake, no ?
While I’m making suggestions, how about a simple directive as a more concise (in fact, simply abbreviated) method for mapping constructors / methods where the mapped member has the same signature ?
Foo = public class mapped to Random
constructor; mapped to constructor;
constructor(seed: Integer); mapped to constructor(seed);
end;
Would become:
Foo = public class mapped to System.Random
constructor; mapped;
constructor(seed: Integer); mapped;
end;
This would obviously fail compilation if the member had no exactly corresponding member in the mapped type.
Well. On .NET, every object has Hash, ToString, and co. It would be weird to be dealing with an object, descendent from Object (like all objects do), and not have access to the members from Object?
I see your point about it making the types different across the platforms WRT those members — but we still gotta respect the class hierarchy.
Yep, an Object is an Object (or an NSObject an NSObject etc), no avoiding that and the methods have to be there and so are bound to be callable by the platform frameworks and app code, no avoiding that either.
But I wonder if it might not be possible to distinguish somehow between mapped and “intrinsic” members in the code completion offerings ? Ideally even emit a warning for code that calls such members if they are used ?
Not sure about that latter idea though. Warnings should be addressable - to indicate to the compiler that you know what you are doing (on those occasions that you do).
i.e. You won’t always want to avoid the platform call, just let the compiler know it’s OK.
Not sure how you would do that in this case. Unless… might it be possible for the compiler to distinguish between an implicit platform call and a typecast call ?
var s := f1.ToString; // Warning: Platform call on mapped type
var s := Object(f1).ToString; // No warning
Or maybe a hint instead of a warning. But you get the idea.
adding a cast would make such a warning addressable, yeah. (Foo as System.Object).Hash).
That said, specifically for ToString, i wanna put more workminto actually making that work on all platforms, because dealing with description vs toString vs ToString becomes annoying, We already dded the [ToString] attribute to let you define a single method, cross-platform. We’ll need to add something similar for calling it (i’ll probably look at just adding a ToString extension method for NSObject, for Nougat…
So to get back to this as it seems I never saw the original. For backward compatibility, if a mapped types does NOT implement any constructors it inherits the ones from the original class, else if it defines any, it doesn’t. There’s no good reason for this left (There was when we wrote it) except for backward compatibility.