wren
wren copied to clipboard
[RFC] Add `static Object.typeOf(_)` (and deprecate `Object.type` ?)
Hi,
While working on the mirror module, I had to implement an equivalent of static Object.typeOf(_). Since Object.type is user over-loadable, it is not safe. Usually these guarantees are required when working with foreign functions.
Since most code does not need strong type guaranties, Object.is(_) is used instead. Because of that, deprecating Object.type should not have a wide impact. In addition is was meant to be overloaded to
I know at least 2 usage for Object.type to be over loadable:
- Reuse the name
typeand rely on the fact that you don't do meta programming (wrenalyzerdid that, to simulateenum). - Augment the class to augment the class data (done in a private experiment). Both of them are crude hack, and can make the user code fragile.
Forbidding the overloading of type is also a solution, but would require a lot of compiler support when generalized (tagging a method final can be interesting but introduce extra inheritance checks, and storage to track final methods)
I suggest that next version at miminum add static Object.typeOf(_). Deprecation of Object.type would be done at next or a future release, while its removal would be due before 1.0.0.
I don't know about anyone else but I use Object.type quite a lot for checking arguments are of the correct built-in type where, of course, inheritance is not a concern and the method is perfectly safe.
As I'm allergic to using a lot of parentheses, I prefer to write:
if (arg.type != Num) Fiber.abort("Argument must be a number.")
rather than:
if (!(arg is Num)) Fiber.abort("Argument must be a number.")
I also occasionally use it in string form where I want to refer to a type in a different module without importing that module.
if (arg.type.toString == "BigInt") { // do something }
I don't know why it was made an instance method in the first place unless it was to allow type 'spoofing' which I think is the second usage you alluded to. That's not something I recall ever doing myself but who knows what other folks get up to!
So, whilst I have no problem with the introduction of a static Object.typeOf method, I'd personally prefer the instance Object.type method to remain and not be deprecated. The situation would then be analogous to the static Object.same method being an alternative to the overloadable == operator.
BTW, if static methods were to become inheritable and presumably therefore overloadable, then this solution wouldn't work anyway unless there was some way to make a static method final.
About your initial concern, it should be factorized to a utility function method in the first place. In the future, you may wan't to return an hypothetical TypeError or whatever. And it also become an opportunity to use !(arg is type) once and forget about it.
If static methods are inheritable, it won't change much, unless one wrongly use arg.type.typeOf(foo) instead of Object.typeOf(foo). Anyway, that error is easily fixable. In the other hand type "spoofing" is not. The VM is not fooled, but from the language there are no solution to get the true type without Object.typeOf(_) (or similar solution, like keyword of what ever).
Well, I'll wait and see whether this change is accepted and what other breaking changes there are in the next version before changing any existing code.
My main concern is the 1600+ Rosetta Code tasks as the code for those is publicly available. I'm not really bothered about my private stuff as I'm forever fiddling about with that!
In the meantime, although I dislike it, I'll try and stick with !(arg is Num) for new stuff. If there were an isnot operator then my objection would disappear as we could then write arg isnot Num without the need for parentheses. I may do a PR to add this as is is the only boolean operator we have which doesn't have a convenient negative form.
Regarding the possibility that static methods might become inheritable and hence overrideable (which, like youself, I now hope doesn't happen) then, on the face of it, people would still be able to do stuff like this:
class MyClass {
static typeOf(arg) {
if (arg is this) return Num
return super(arg)
}
construct new() {}
}
var mc = MyClass.new()
System.print(MyClass.typeOf(mc)) // Num
Incidentally and pedantically, I think we've both been guilty in this issue in talking about 'overloading' when we really mean 'overriding' inherited methods :)
This is the reason I said you should abstract the behavior in a function,
like in the assert library. Duplicating even a one liner is a bad idea...
Don't give me more work for operators in veery :) when I'll publish it,
check if I did not forget to add it. It will probably be is not.
Your concern is not founded, since one as to call explicitly
Object.typeOf(arg). Unless someone, use type.typeOf(arg) the concern is
minimal. (Another task for veery type_of keyword)
This is the reason I said you should abstract the behavior in a function,
As it happens, I already have this in the form of my check module which can validate arguments of all kinds not just for type but for range as well. Curiously, I've used the !(arg is type) syntax throughout in this module so I must have had a premonition that this issue was coming :)
However, I introduced this late in the day and have used it mainly for inter-module checking. I haven't used it directly very much as I didn't want to ask people to import a 350 line module just to run a short script. But anyway that's my problem.
OK, I'll refrain from doing a PR for isnot if it's something you already have in hand for veery :)
I don't have right now, but it is a simple node transform. So it is only a matter adding the tokens, matching them into a node and performing the transform in the wren translator.
OT @PureFox48 out of curiosity do you have command line argument parser ? I have one that is not really OO and quite a lot manual (though I can factorize it to be OO)
No, it's not something I've bothered to write.
There's one here though it's probably too simple for your needs.
Too simple but confirms that what I do is right, it is only a matter of making it more OO then ;)