Open masak opened 6 years ago
I'm too tired to think about all the implications, but it sounds like this could be very interesting, especially WRT what a 007 MOP could do.
I'd like to playfully nickname this issue The Curse of Girard.
Here's one thing that would be desirable to be able to do with subtyping of Type
:
As far as I can see, the straightforward implementation of #265 is just something like this:
my $enum = _007::Type(:$name, :fields["name"]);
declare-in-scope($name, $enum); # *handwave*
for @enum-values -> $v {
declare-in-scope($v, create($enum, :name($v)));
}
(I just re-aligned the #242 branch so that there's no longer an internal _007::Object::Enum
type. That is, enum values such as None
and True
play under exactly the same rules as ordinary types and values in 007.)
Now one problem is that someone could instantiate a new enum value from the enum type. This is unfortunate, because runtime instantiation of enum values ultimately degrades the usefulness of enum types. (Java and Python certainly forbid instantiating enums. Perl 6, surprisingly, allows this.)
Since MyEnum.create(...)
would be how you create new enum values, I'd like to override the .create
method on MyEnum
. Since we don't override methods per-instance in 007 (yet, at least), the way I'd have to do that is by subclassing Type
into, hm, EnumType
and providing it with a new create
method. One that just dies when you call it.
Another problem is if someone tries to subtype MyEnum
. I'm not sure being able to do this is on par with being able to instantiate it — especially if you can't create instances of the subtype either, but I'm not sure offhand we can enforce that... *brain explodes* — but let's assume it is. The problem now is that subtyping MyEnum
doesn't happen as a method call on MyEnum
, it happens as Type.create
(or EnumType.create
— which, note, is distinct from the overridden MyEnum.create
). We could override EnumType.create
too, I think, by leveling up and creating an EnumTypeType
. I'm not 100% sure I like that.
Better perhaps to find a way to affix an @Unsubclassable
trait (Java would call it @Final
) to the EnumType
class. And then have the built-in create
respect this when checking the :base
parameter.
I need to stop writing now, because my head is spinning from walking up and down the spiral staircase of type levels.
Thinking about this some more, I realized that in order for us to effectively have types with custom types, _007::Type
needs to have a $.type
attribute. Another way to say this is that "the type of a type object is (exactly) Type
" is an oversimplification — it's enough to type-match with Type
, i.e. it can be a subclass.
In retrospect, that's fairly obvious, and I suspect I'd've come to that realization through some other route towards the end of #242. It falls out of Type
needing to be, in all aspects, a subclass of Object
— which has a type
property.
I already implemented this in 5dc3031f54c73219241f92a942efe56eefd87e4c and 7184e0854114a6d9ff628c218dab8f53a5256ba7. I've yet to write tests for it, though.
(And it doesn't stop there. _007::Type
will need to have %.properties
and method definitions just like _007::Object
. Certainly merits writing a few tests.)
Thinking about this some more, I realized that in order for us to effectively have types with custom types,
_007::Type
needs to have a$.type
attribute.[...] (And it doesn't stop there.
_007::Type
will need to have%.properties
and method definitions just like_007::Object
. [...])
And, since they will share so much structure, maybe _007::Type
shouldn't exist separately at all? The main reason it does right now is that this gives us a quick way on the Perl 6 level to check whether some object is a Type
object. But there are other ways to do that.
Interestingly, Smalltalk doesn't have a concept of static
methods, it implements methods on the type/meta objects, much like I'd hope we could do in 007. Also quite similar to method ^foo
in Perl 6, although in Perl 6, type objects and meta objects are two distinct things.
the way I'd have to do that is by subclassing
Type
into, hm,EnumType
I think elsewhere in the issues I've called that new MOP type Type::Enum
. Maybe that's a more stylish name.
Better perhaps to find a way to affix an
@Unsubclassable
trait (Java would call it@Final
) to theEnumType
class. And then have the built-increate
respect this when checking the:base
parameter.
When I thought about this the other day, it seemed to be the reasonable thing to do. The subtyping relationship is kind of reversed to how we'd want it — the base type is oblivious to its derived types — and so in that case, enforcing that something can not be subclassed needs to be left up to the OOP system itself.
Subclassing is quite straightforward in the post-#242 world: you just do
_007::Type.new(:name<NewType>, :base($basetype))
.But what exactly happens when
$basetype
isTYPE<Type>
? I'm asking because I don't exactly know.There are at least two parts to this question:
We'll need to follow slightly different code paths here, probably, since on the Perl 6 level
_007::Object
and_007::Type
are distinct types. (Does your head hurt too? Not just me? Good.)In some sense,
Type
(on the 007 level) is our MOP and governs exactly what we can do with it. If we manage to subclass it, it would follow that we can specify new things we can do with it — i.e. extend the MOP itself. What exactly does this entail? Trying to be specific, what can we do with new fields and methods on aType
subclass? Can we override some of the old methods, for example.create
? What else can we do? Inquiring minds want to know.