Classes mega-RFC - #242
Conversation
Also introduce the `open` keyword to allow classes to explicitly opt into inheritance.
|
Since we're moving discussions to this thread, I'd like to link some of my previous comments that I believe still holds important value for constructors: |
To summarize, I believe the two main points of concern are:
I can't speak more on the first point beyond saying that this is a hard requirement from internal stakeholders, but maybe @andyfriesen can. On the second, we share your concern, and have included your suggestion that child classes must define constructors if their parents do so! This is specified in Constructors - Typechecking. |
I would really want the team to present all of these potential pain points in implementation and syntax to internal stakeholders. We have seen this play-out before, and it is understandable that the team would consider their requirements first, because, well, Roblox is the primary customer, but this requirement benefits no one. There can be workarounds found for those who wish to easily have a method such as I've also proposed the The team could also consider implementing C++ like template classes, with generic support. C++'s template classes are quite useful, and if brought to Luau in a way that doesn't increase the syntax complexity too much, it would be an amazing alternative. The user would create a class from a template that contains I would really suggest that the team listens the community on this one, because I believe community will use classes more than anyone else. If this requirement stays, then I believe the community backlash and confusion will be imminent. For the second point, Andy did update the previous RFC to include an additional rule about that, so that was great. |
I agree. The RFC states the motivation behind this by saying:
This is really just enforcing a status quo rather than guaranteeing consistency due to the drawbacks of making a |
|
The main concern I have with Since there is only 1 constructor, when designing a class you have to make sure that constructor really counts. If there are any static factory methods, this 1 constructor must support constructing a class in any way the factory functions support constructing the class. If there are no invariants and all properties are public, this is fine, since the default constructor will work for this, but when you start needing invariants (or if private properties become a thing), this becomes problematic. If you just make a simple constructor that allows setting the properties in any way (or use the default constructor), invariants become difficult to enforce. Perhaps you could enforce the invariants through assertions in the constructor, but the invariants may be difficult or slow to check without additional context from the factory methods, and you might not want some properties to even be settable from outside of public code. It would just quickly become a mess as you add more factory methods, each with their own rules for what is allowed. So, the simple solution one might do is to instead just make the constructor private but powerful and with no enforcement of invariants (obviously private doesn't exist right now, but we are looking to the future). Then, invariants can be enforced in the factory methods where they have full context, and the factory methods can construct arbitrary class objects however they need. This is very similar to what Rust requires you to do. However, because we have made the constructor private, we are now blocked from using a constructor named Languages like C++ and Java bypass this problem by allowing you to overload a private, more powerful constructor. That isn't really an option in Luau, however. |
* tweak __eq rule * tweaks
|
This might be too little too late since the discussion around inheritance has pretty much settled down, but is there any chance the concept of abstract class Base
abstract function method(self, x: number|string): {}?
end
class ChildOne extends Base
function method(self, x: number|string?): {x: string}
return {x="hello"}
end
end
class ChildTwo extends Base
function method(self, x: number|string?): {x: string}
return {x="other"}
end
end
const function operateOnClassObjectsWithMethod(object: Base)
object:method("stuff")
endThe example function accepts a parameter
If The other aspect of I know the whole inheritance thing is pretty much settled at this point, but I feel like existing discussions overlooked a lot of the key functionality that |
|
Hello! We've had both interface inheritance and marking individual methods as |
I'd also love to see abstract classes eventually. I personally think they should be a part of the classes syntax rather than a new "interface" syntax. Would make things easier and more consistent. Though comes the question, if we're going to use |
* forbid overriding comparison metamethods. * note that `__eq` doesn't throw * may reserve other metamethods
Rendered
Per the discussion on OSS Discord, this collates the existing PRs into a single "mega-RFC" that once merged, will serve as the source of truth for how the final feature should behave.
Future class-related features should be proposed as PRs against this branch, and once those discussions have settled, this PR will be merged.
I've taken the liberty of updating the existing RFCs slightly as I collated so that the full document is internally consistent.
The mega-RFC reflects the team's stance on what classes with just the features discussed should look like. This stance may change as we consider additional features, and PRs against this branch will update existing sections if necessary.
Future discussions on the general design of classes, constructors, and implementation inheritance should take place on this thread.