-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do tuples need a shared non-Object
superclass?
#1290
Comments
For the shared properties, maybe the dynamic type of a This won't allow for the same level of introspection as the record proposal's We could also consider a getter |
Even if we do that, I still think they should have a more precise type that they accept beyond just
Records as I've proposed them aren't really like strict product types. That model falls down when you consider that a record with a single named field is still clearly distinct from the field's value. (This is part of the reason I call them "records" and not "tuples".) I think it's better to think of them as immutable heterogeneous collections. From that perspective, there's no reason not to support a one-positional-field record.
Record types may not have any members in common now, but that doesn't mean that users might not want to define extensions shared across all record types. I admit the body of that extension doesn't have a ton of useful affordances on Basically, I think providing Record as a tag interface is relatively harmless and potentially useful, so I lean towards just doing it. |
Nobody would be passing tuples into anything. You'd do |
In 98341cd, I removed the reflective methods on There are places where users write functions that accept one of a handful of known types. In the absence of overloading, they usually just accept |
Is there risk in experimenting, or even shipping, without the |
Yes, I think we could do that. We essentially did the same thing with I think it's fairly harmless to add it eagerly, and I do think it's useful and something users will occasionally want. Also, all of our other structural types have a corresponding supertype: |
Out existing supertypes have funcitonality. The interface methods are not the only reason these types to exist. I use For example, if we rewrite |
Yes, I think this is the primary motivation for having a /// Does some useful thing with the given [tuple], which should be a record
/// with only positional fields up to arity ten.
doStuffWithTuple(tuple) {
switch (tuple) {
case (f1, f2): ...
case (f1, f2, f3): ...
case (f1, f2, f3, f4): ...
...
}
} Having a I'm going to leave |
@munificent, the proposal says
meaning that It's true that you would lose the ability to say "this function accepts records only", but any amount of arguments can be packaged into a corresponding record (including a 1-element positional record), so I don't see the need for that distinction. On the other hand, there may be valid reasons for wanting an object over a record, like |
If It's not how it's modelled, though. You can nest records! (One of my many prototypes of records tried to disallow that, making The problem with having any proper supertype of It's not entirely new, we did it with But surely that's fine, because no existing code uses records yet, so they can just change when migrating and starting to use tuples, right? But the, we could just say that "no bound" means a bound of But we could automatically change all We also need to consider interaction with older code. If we introduced records in, say, Dart 2.20.0, the what is Dart 2.19.0 code going to do if it sees a record. I think we can make We'd also probably want another supertype, say Choosing to make (Will we want a type which means "non-Record object"? Say |
Then the test |
I definitely understand how massive a change it would be to replace
In this comment I position
I'll copy from there what I think the benefits could be:
And it also answers this question about a non-Object type:
It sounds like "not a real object" would mean it's more useful to ask, "is this an |
If we go fully hypothetical, then your hierarchy makes sense. I wouldn't call the top The question is what the other subtypes of If the subtypes are If the subtypes are The way I see things today is that Pragmatism for the lose (and win!) |
The proposal for tuples have a
Record
class which acts as a common supertype of tuple types.Whether that is necessary or desirable depends on perspective and features.
The main reason for separate types to have a shared supertype is either having a shared interface or other shared affordances.
For example function types have a common supertype
Function
which abstracts over their ability to be called (they have a "dynamiccall
" member), and people are asking for a supertype of enums, which have a sharedint get index;
interface member.So, the question is whether tuples should have any shared functionality, and if not, whether they should have a supertype anyway, for good measure.
The proposal suggests that the
Record
class have methods which reflect on the tuple. Those work on all tuples, and only on tuples, and therefore need an argument type ofRecord
.I would prefer to not add such functions outside of
dart:mirrors
, and then they would be part of aRecordMirror
, not something which works on the reified tuple itself. If they exist outside of mirrors, the functions could also take any object as argument, and treat non-tupes as if they were one-tuples containing the value (I also argue that there should be no one-tuples because the product type T^1 is just T, so that would be consistent).There is no other shared functionality between tuples, those two reflective functions are the only ones which work on tuples independently of the tuple "width"/"arity"/"structure". There is no shared interface members between
(int, int)
and({int x})
, so without those two method, there is no advantage in knowing that something is a tuple, because you still don't know which tuple structure it is (and there is a countably infinite number of those if you try to do an exhaustive search). You're better off casting todynamic
if you want to explore the members of an arbitrary tuple, than by trying to cast to a tuple type.If there are no empty tuples (or even no singleton-tuples), the
Record
type also feels incomplete (to me). It's true that it contains all tuples, but with that view, maybe a single object is a one-tuple, so why isObject
not a subtype ofRecord
?Still, people like to have categories and be able to express those categories in code. Saying that a variable is a
Record r;
is documentation that is statically and dynamically enforced (whereasObject tuple;
is just text, no enforcement).(Betteridge's law says no.)
The text was updated successfully, but these errors were encountered: