-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Move DateTime
constants for month and weekday into extension types.
#60669
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
Comments
Could work. Would probably still be available in |
Can't we implement the various units as extension types without breaking backwards compatibility? It should work if we keep the identifiers the same and the different units still implement class DateTime implements Comparable<DateTime> {
...
static const Weekday monday = Weekday(1);
static const Weekday tuesday = Weekday(2);
static const Weekday wednesday = Weekday(3);
static const Weekday thursday = Weekday(4);
static const Weekday friday = Weekday(5);
static const Weekday saturday = Weekday(6);
static const Weekday sunday = Weekday(7);
static const Month january = Month(1);
static const Month february = Month(2);
static const Month march = Month(3);
static const Month april = Month(4);
static const Month may = Month(5);
static const Month june = Month(6);
static const Month july = Month(7);
static const Month august = Month(8);
static const Month september = Month(9);
static const Month october = Month(10);
static const Month november = Month(11);
static const Month december = Month(12);
...
} Any computations which processed the units as |
The constants still need to be defined inside the But you could update the types of the existing constants also. |
The problem here is that changing the parameter type to We can make If we don't change the parameter type, and keep it as So, sadly it's not possible with the current feature-set, not without breaking far too much code. |
You are correct, I only considered usages of the constants directly. It would be very breaking to make the changes because So it would only make sense to do as @mmcdon20 originally proposed, and add the new types while keeping the original class as it is. Then new constructors, methods, etc would have to be added to |
Thats unfortunate. I think it can be made to work with any of the following, but some of these might work better than others:
|
This is basically the motivating example for the parameter default scopes: We want to provide certain distinguished values by name (available as dot shorthands) in a situation where it does not make sense to add said names to the static namespace of the type (concretely: An important property of this approach is that the weekday and month values are still of type Let's assume that we have static extensions, e.g., this proposal, such that we can provide a set of declarations in their own static namespace and also inject them into another static namespace (here: class DateTime implements Comparable<DateTime> {
// Remove `monday` .. `friday` and `january` .. `december`: Moved to static extensions.
...
DateTime(
int year, [
int month = 1 in Month,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0,
]);
...
external int get weekday in Weekday; // Enable dot shorthand constant patterns.
external int get month in Month; // Ditto.
...
}
static extension Weekday on DateTime {
static const int monday = 1;
static const int tuesday = 2;
static const int wednesday = 3;
static const int thursday = 4;
static const int friday = 5;
static const int saturday = 6;
static const int sunday = 7;
static const int daysPerWeek = 7;
}
static extension Month on DateTime {
static const int january = 1;
static const int february = 2;
static const int march = 3;
static const int april = 4;
static const int may = 5;
static const int june = 6;
static const int july = 7;
static const int august = 8;
static const int september = 9;
static const int october = 10;
static const int november = 11;
static const int december = 12;
static const int monthsPerYear = 12;
} We can now use void main() {
if (DateTime.now() case DateTime(weekday: .saturday || .sunday)) {
print('today is a weekend');
} else {
print('today is a weekday');
}
} An |
@eernstg With this approach, What would happen if you wrote: void main() {
final weekday = DateTime.now().weekday;
if (weekday == .saturday || weekday == .sunday) {
print('today is a weekend');
} else {
print('today is a weekday');
}
} Would it still work? |
Yes, it would @mmcdon20, the last example in the comment above is basically the same thing you wrote, but uses pattern matching instead of expressions to test on weekends. |
I'm not sure it would work because the default scope is now on the |
I understand your question now, I guess I'm not that familiar with the parameter default scope feature to answer. If that got carried over to the variable, or maybe you could explicitly write that, I'm not sure. Thanks for explaining. I'll see the discussion for the feature to try and answer. |
void main() {
final weekday = DateTime.now().weekday;
if (weekday == .saturday || weekday == .sunday) {
print('today is a weekend');
} else {
print('today is a weekday');
}
} No, So that's basically an impossible task (or, at least, it would call for some very twisted tricks ;-). It would work, though, if |
Alright, that's what I thought would happen.
I think I would prefer the implicit constructor feature over default scopes due to cases like this. |
It's an interesting pair of strategies. In both cases we enable dot shorthands by adding declarations of the desired distinguished values
The first strategy is less disruptive because it allows The second strategy is more "sticky" in the sense that a type like By the way, I'd like to have something along the lines of parameter default scopes (that is, some mechanism that allows us to customize which static namespace to search for a dot shorthand) and implicit constructors. ;-) |
Out of the various discussed alternatives, I think the ones that would be the easiest to integrate in existing code bases and easy to pick up as a new feature would be (1) static extensions with (2) overloading. Then issues such as this one are solved simply by declaring what's needed without needing to reason about what namespaces are set or even having to introduce new ones. |
Based on @eernstg's comment (dart-lang/language#3834 (comment)):
I'm not sure what the benefit of using a class in this situation over the extension type would be. I do see a potential benefit in modeling Something like this: enum Weekday {
monday,
tuesday,
wednesday,
thursday,
friday,
saturday,
sunday;
static const int daysPerWeek = 7;
}
enum Month {
january,
february,
march,
april,
may,
june,
july,
august,
september,
october,
november,
december;
static const int monthsPerYear = 12;
}
static extension on Weekday {
implicit factory Weekday.fromInt(int i) {
return Weekday.values[(i - 1) % Weekday.daysPerWeek];
}
}
static extension on Month {
implicit factory Month.fromInt(int i) {
return Month.values[(i - 1) % Month.monthsPerYear];
}
}
static extension on int {
implicit factory int.fromWeekday(Weekday weekday) {
return weekday.index + 1;
}
implicit factory int.fromMonth(Month month) {
return month.index + 1;
}
} Edit: thinking about it some more the above would very likely be breaking. void main() {
final today = DateTime.now().weekday; // enum implementation above
print(today + 1); // I don't think this works even with implicit conversion
} So because a regular class, or an enum can't implement or extend |
I think the "sticky" behavior is likely what most users will want when using/designing an api with dot-shorthands. |
Currently
DateTime
has the following definition:I propose that we deprecate the constants in
DateTime
and create extension types to represent theMonth
andWeekday
.The reason for this change is to better enable the upcoming
dot-shorthands
feature.The proposed change would allow us to write for example:
The text was updated successfully, but these errors were encountered: