-
Notifications
You must be signed in to change notification settings - Fork 82
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
MonthOfYear
data type
#134
Comments
The |
Would prefer not to proliferate types. |
I'm not sure what you mean. This would be safer than |
Should there be a |
Is this a good idea? |
I wouldn't say so, just because |
OK, so we have to allow invalid year-month-day representations anyway. I'm not seeing the benefit of a month type. In any case, dates come from numbers (which can be invalid) or text (which can be invalid). Use |
Maybe, but that doesn't mean you have to allow for invalid month representations. |
To expand on this, I have to do exactly this, here: https://github.com/NorfairKing/smos/blob/4c0c53e46b2645ede1f7a963e68045e631bfbf6e/smos-calendar-import/src/Smos/Calendar/Import/RecurrenceRule/Type.hs#L259-L262 |
Why does it matter if there are invalid month representations, when they have to be validated anyway? |
The short answer: There are numerous reasons; for example to be able to generate them without writing the generator manually. |
In that case I recommend creating your own month type. In the time library, validation of year-month-date formats cannot be avoided, and it's easier to consistently use |
This would also make it possible to add an |
I would probably represent that as a newtype of an Integer (an absolute count of months). |
Then you have the worst of both worlds: It's both still mostly invalid (because it's still just an int) AND you have to deal with an extra type. |
Oh, I meant for a year-and-month type for, for example, "May 2020". Using a newtype for an Integer would have no invalid values. |
A new |
I just don't see how this is any different from #69. The Once an integer has been parsed as a Month, it should be reflected in the type system, especially when there are already built-in functions for converting to and from integers safely. |
There's no canonical numbering of days of the week, so a type makes sense. By contrast, month-of-year and day-of-month have canonical numberings. |
ISO 8601 defines a numbering for weekdays: 1-7 (https://en.wikipedia.org/wiki/ISO_week_date). Nevertheless it's still better to use Monday-Sunday, as it would be better to use January-December. I can't believe that we even have to discuss this 🙄. |
Reminds me of this gem by @justinwoo 😂😭 |
Any chance of this being re-opened? I think it's a real shame that a core library isn't exposing a more idiomatic Haskell-y API. I've just hit this today. I get a I've ended up defining my own sum type and conversion functions, as I imagine other people in this thread will have done. But, in general, if every user of a library is writing the same wrapper around it, that's usually a sign something should be upstreamed. |
Hmm, should we also have a
|
The difference is that every year always has twelve months, and the twelve months listed above are always present in a given year. There won't ever be invalid pattern matches like there will be with |
@bi-functor We're going in circles now: #134 (comment) |
I see. What about |
If each minute had its own name? I would agree, there should be a type to represent that. But they don't, they are literally named by their number. If there was an easy way of representing modulo 60 at the type level, that would be ideal. Each month has its own name. |
@AshleyYakeley If you ask "Why does it matter if there are invalid month representations, when they have to be validated anyway?", why even store these numbers as numbers and not just bytestrings? You have to validate the bytes anyway. |
I hope we’re still on this. The arguments against it are as weak as they were 3 years ago IMHO. ^^ |
In any case, I've made the guiding principles quite clear. |
Simplicity over safety is actually pretty important for a library used as much as this. Copying from another issue: As an example of the cost in simplicity, consider two scenarios:
|
I'm sorry I don't have time for a detailed response right now, but quite simply, if every library followed that logic, I wouldn't use Haskell. |
Does creating a I mean, in a few cases, you might hard-code But in every other possible construction of the Anyway I've explained my reasoning, the principles and how they apply, with no more response than a thumbs-down emoji. TBH I'm beginning to think you've all kind of dug in here, having run out of arguments? |
I agree with another user's point of "parse, don't validate". The ideal situation is once your inputs are parsed, you shouldn't have to make sure that they're correct in future. Type synonyms don't enforce that at all, and can disguise issues. If I parse what is meant to be a date in JSON, I don't want I believe many people are just using reactions because the points being made are just being dismissed out of hand. For point one you would only have that partial function of the m value is invalid; and if it is, you shouldn't be constructing the year month day value anyway! For point two, you would only have to validate twice if you don't carry around the proof that you parsed it correctly. Instead of a data type you could have an opaque newtype around an Int or Word8 or similar, with |
I'll happily argue about this for as long as you want. In my view there are two really good arguments for you to make that I'd begrudgingly accept:
Unfortunately this is a boot library. Otherwise I'd have forked it long ago and not bothered you with this. The only reason I haven't done that is because I am now convinced that you just don't like me. |
Why are you still using haskell, then? There are safer, lower-level alternatives like rust. |
I really don't think we need to be suggesting to kick each other out of the community over these types. I'll admit that my suggestion to add pattern synonyms for the The reason I usually want a |
OK, finally someone gives an actual realistic code scenario.
You can already do this.
It's not clear this would be appropriate even with an enumeration type. I do this for
I don't understand -- if you obtain a |
The fact of the matter is that the I'm not convinced any of the people complaining are running into genuine safety issues in their own code, where using an enumeration type would actually catch potential defects at compile-time. Rather, you seem to be thinking entirely abstractly about the type. Haskell encourages this sort of thinking, of course, but it doesn't mean it's always appropriate for working code. If I make this change now, obviously, lots of people will complain about the sudden (pointless!) incompatibility. If I had done it this way from the beginning, lots of people would complain about how awkward it is to construct And literally no actual safety would be gained. None of your code defects would be caught at compile-time. It's all abstraction. |
I've already shown you several real footguns and actual dangers Here are some more:
Should be a parse error, and is silently both wrong and invalid instead. ^ This one is extra fun when it's part of a bigger string like
Should be
Should be
Should be a compile error, and is silently nonsense instead.
Should be a compile error, and is silently invalid instead.
Should be a compile error, and is silently nonsense instead.
Should be a compiler error, but is silently nonsense instead.
Most of these are silently invalid. Note that all of these perform operations that the compiler is convinced should "just work".
If you know anything about my work you'll know that the topic of mental masturbation is not one I take lightly. |
These are all, at most, arguments for removing the type synonym But regardless of the existence the type synonym and patterns, can you at least agree that month-of-year should be an |
I don't know if it should but I agree that it's a good idea that the option exists. For |
Also, should the |
This means duplicating a bunch of functions, which I definitely want to avoid. In order to keep things simple, I prefer to stick to one type for any given concept. And for month-of-year, it has to be |
Yes, actually. |
If that duplication can introduce safety that wasn't there before then I'm all for it. |
It introduces no more safety than an |
@AshleyYakeley It does because not every day has 24 hours but every year has 12 months. And an |
@AshleyYakeley #134 (comment) |
Actually, many systems (including popular Java / java.util.Date)) use [0..11] which leads to a further confusion when you work with multiple platforms. Having one int less to worry about, thanks to a proper type, is a nice idea. |
I'm in favour of @NorfairKing's API design. However, whether the current API should be changed to that design is a different matter. One downside is that it would be a breaking change. Another downside is simply that it goes against the preferences of the maintainer; that's an important consideration. I don't use
I don't understand why. |
This is not correct: every day has 24 hours. More specifically, every day has an hour-of-day in the range
Do you even believe this? How would an I think people here are being fooled by the fact that in their culture/language, there are names for the months, but not names for the hours of a day. So they think the first should be an ADT but the second should not be. But from a calendrical & software point of view, they're very similar. |
So there are two issues here:
(1.) is the actual issue described here. Let me repeat why this would add complication to actual practical code:
And what would the safety benefit be? What defects would it prevent? All of your (highly contrived) examples of bad code have been due to issue (2.). Regarding (2.): I feel this is a worthwhile trade-off of convenience for safety. It's true, someone might make the mistake of thinking they were ADTs if they don't read the documentation and use something like |
In the first case, there is no guarantee that your Int triple is correct, and use of a partial function shows how dangerous the current implementation is. If you can't prove that a month is a valid month, then you shouldn't be able to make it! Further, the point others have made about different systems using different indexing for months further shows how having a "valid" month can still be incorrect. In the second case, this is very easily solved by just moving the validation for month inside that function, (which it looks like you already do in Data.Time.Calendar.MonthDay) or you could have different sorts of validation functions, where one takes a year and a valid month and an integral day and says whether that's valid, and that's wrapped up inside one that takes an integral month. Neither of these cases are good arguments against using an ADT. |
Yes there is, you already have that guarantee as a premise to the case. I'm giving two examples here, one where you already know it's correct (and therefore have no need to validate), and one where you don't (and therefore you need to validate).
Right, we already have that with
So this means duplicating all functions and patterns that work with month-of-year. As a matter of simplicity, I avoid having different types for the same concept. |
Folks, this issue is closed. I recommend you create your own |
We already have
DayOfWeek
; this structure (and relevant instances and functions) would be handy as wellThe text was updated successfully, but these errors were encountered: