Is it possible to modify language in a way to make >,<, = work for dates?
The datetime's struct has known values <https://github.com/elixir-lang/elixir/blob/v1.14.1/lib/elixir/lib/calendar/datetime.ex#L110-L123> which can be pattern matched against and struct comparison, in general, is not used that match, so it shouldn't mess up with already written code (maybe we even fix couple bugs as using >,<,= to compare dates are relatively common first bug for new elixir developers). If we can ducktype struct with such attributes and use a regular DateTime.compate/2 to compare it in Kernel.>/2 function and friends. > On 31 Oct 2022, at 19:54, Cliff <notcliffwilli...@gmail.com> wrote: > > I did some more playing around and created this macro: > > defmodule Foo do > defmacro compare_with(comparison, module) do > {op, _env, [a, b]} = comparison > > cmp_result = quote do > unquote(module).compare(unquote(a), unquote(b)) > end > > case op do > :> -> > {:==, [], [cmp_result, :gt]} > > :< -> > {:==, [], [cmp_result, :lt]} > > :>= -> > {:!=, [], [cmp_result, :lt]} > > :<= -> > {:!=, [], [cmp_result, :gt]} > end > end > end > > I don't think it is actually a good solution to this issue, but just wanted > to share the idea. > > (a >= b) |> compare_with(DateTime) > > On Monday, October 31, 2022 at 2:46:09 PM UTC-4 benwil...@gmail.com > <http://gmail.com/> wrote: > > DateTime.compare(a, :<, b) would get my vote of the alternative proposals > > but I think it doesn't move much the needle in comparison to > > DateTime.compare. > > To me this is a pretty big difference difference, because with an `import` it > does 2 things: > > 1) Eliminates the existence of an irrelevant, boilerplate operator == > 2) positions the 2 values you care about correctly with respect to the > relevant operator > > When you have > > DateTime.compare(a, b) == :lt > > it's like RPN, you have to hold a and b in your head, remember their order, > then skip past the `==` since it doesn't matter, and finally you get to see > your comparison. When discussing this in complex contexts the need to try to > distinguish about whether you're talking about what the _function call is > equal to_ from whether the values themselves are equal to is actually a > pretty big deal. There are basically 4 characters with semantic value, and > there rest are boilerplate. When you have a bunch of these all next to each > other (like when building up complex range helpers) > https://gist.github.com/benwilson512/456735775028c2da5bd38572d25b7813 > <https://gist.github.com/benwilson512/456735775028c2da5bd38572d25b7813> it's > just a ton of data to filter out. > > If you could `import DateTime, compare?: 3` this could be > > compare?(a, :<, b) > compare?(a, :<=, b) > > On Monday, October 31, 2022 at 2:02:03 PM UTC-4 Cliff wrote: > > in Elixir the subject is always the first argument > > Ah, that clears it up for me, I hadn't yet realized that symmetry in the > APIs. I like the before?/after? functions now. > > On Monday, October 31, 2022 at 1:16:52 PM UTC-4 José Valim wrote: > I am not worried about the argument order because in Elixir the subject is > always the first argument. So it is always "is date1 before date2?". I like > the :inclusive option if the need ever arises. > > DateTime.compare(a, :<, b) would get my vote of the alternative proposals but > I think it doesn't move much the needle in comparison to DateTime.compare. > > On Mon, Oct 31, 2022 at 5:44 PM Cliff <notcliff...@gmail.com <>> wrote: > I would prefer the atoms :before, and :after rather than > :gt/:greater_than/etc. Since we're already solving the problem of > operator/argument ordering, why not remove the final mental barrier of > reasoning about whether a time being "greater than" another time means that > it is before or after? foo(a, :gt, b) still requires a second thought ("Is a > bigger time earlier or later?"), whereas if I read code that said foo(a, > :before, b) I would feel confident in my understanding after only the first > read. > > On Monday, October 31, 2022 at 12:35:05 PM UTC-4 lui...@gmail.com <> wrote: > I also prefer something like DateTime.compare(a, operator, b). > > Operators don't need to be cryptic like :eq, :gt, :lte, etc., we can use the > same comparison operators we already are used to: > > DateTime.compare(a, :<, b) > DateTime.compare(a, :==, b) > DateTime.compare(a, :>=, b) > > It's clear and much less verbose than the Ecto's (which was a great > suggestion, by the way). > > On Monday, October 31, 2022 at 5:23:54 PM UTC+1 and...@dryga.com <> wrote: > Hey guys, as an idea why don't we reuse atoms from Ecto: > :less_than > :greater_than > :less_than_or_equal_to > :greater_than_or_equal_to > :equal_to > :not_equal_to > I feel like they are fairly common nowadays and even though it's more to type > make it easier to understand when you want an inclusive comparison. > > We can later make it part of all modules that have `compare/2` (Date, > DateTime, Time, Version, etc). > > On Monday, October 31, 2022 at 10:10:09 AM UTC-6 Cliff wrote: > I prefer the form DateTime.is(a, operator, b), but I agree with others that > it would need a more sensible name than "is". > > Regarding the form DateTime.before?(a, b), I could still see myself getting > confused by argument order. before?(a, b) might be read as "before A > happened, B happened", rather than the intended "A happened before B". the > is(a, :before, b) form, however, is read exactly how it would be spoken. > > Regarding comparison inclusivity, another possibility is a keyword option: > DateTime.before?(a, b, inclusive: true) > > On Monday, October 31, 2022 at 3:45:15 AM UTC-4 simonmc...@gmail.com <> wrote: > DateTime.before?(a, b) is much nicer than DateTime.compare(a, b) == :lt. It > doesn't completely remove the argument order issue but I reckon it would > resolve it for me. I run DateTime.compare(a, b) in iex every time I use the > function because I'm terribly forgetful and paranoid. I would prefer > DateTime.eq?/lt?/le?/gt?/ge? instead of > before?/after?/on_or_before?/on_or_after? which is shorter, matches compare/2 > and might allow the le/ge equivalents to sneak through. I think it would be > a shame to leave out le and ge. > > DateTime.is?/compare?(a, :lt, b) is a whole lot less ambiguous to me. It > reads how you would write it in maths or spoken language. > > On Monday, 31 October 2022 at 5:08:35 pm UTC+10 zachary....@gmail.com <> > wrote: > I wonder how much of the issue is the Api and how much of the issue is just > the docs? I.e its not a given that all arguments in every position always > make sense, but we typically rely on things like elixir_ls to help us when > the answer isn't obvious. > > Could we perhaps just improve the docs in some way? i.e update the specs to > say `datetime :: Calendar.datetime(), compares_to :: Calendar.datetime()`, > and have the args say `compare(datetime, compares_to)` and have part of the > first line of text say something a bit more informative? > > > On Mon, Oct 31, 2022 at 3:02 AM, Jon Rowe <ma...@jonrowe.co.uk <>> wrote: > I'm not sure the name is right, but I like > >> DateTime.is?(a <http://datetime.is/?(a>, operator, b), when operator :lt | >> :le | :eq | :ge | :gt, which would capture the :le and :ge options. > > As a usage api, we could actually have `compare?/3` especially as the name > doesn't overlap with `compare/2` which would hopefully alleviate anyones > concerns about the return type changing > > On Mon, 31 Oct 2022, at 6:23 AM, José Valim wrote: >> My thought process is that a simple to use API should be the focus, because >> we already have a complete API in Date.compare/2 <http://date.compare/2> and >> friends. > >> On Mon, Oct 31, 2022 at 02:16 Simon McConnell <simonmc...@gmail.com <>> >> wrote: > >> would we want on_or_after? and on_or_before? as well then? Or something >> like DateTime.is?(a <http://datetime.is/?(a>, operator, b), when operator >> :lt | :le | :eq | :ge | :gt, which would capture the :le and :ge options. >> >> On Monday, 31 October 2022 at 7:26:42 am UTC+10 José Valim wrote: >> Thank you! >> >> A PR that adds before?/after? to Time, Date, NaiveDateTime, and DateTime is >> welcome! >> >> >> On Sun, Oct 30, 2022 at 6:46 PM Cliff <notcliff...@gmail.com <>> wrote: >> I did a bit of research. Many other languages use some form of operator >> overloading to do datetime comparison. The ones that do something different: >> Java has LocalDateTime.compareTo(other) >> <https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/LocalDateTime.html#compareTo(java.time.chrono.ChronoLocalDateTime)>, >> returning an integer representing gt/lt/eq. There is also >> LocalDateTime.isBefore(other) >> <https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/LocalDateTime.html#isBefore(java.time.chrono.ChronoLocalDateTime)>, >> LocalDateTime.isAfter(other), and LocalDateTime.isEqual(other). The >> LocalDateTime.is <http://localdatetime.is/>{Before, After} methods are >> non-inclusive (<, >) comparisons. They are instance methods, so usage is >> like `myTime1.isBefore(myTime2)` >> OCaml's "calendar" library provides a Date.compare >> <https://ocaml.org/p/calendar/3.0.0/doc/CalendarLib/Date/index.html#val-compare> >> function that returns an integer representing gt/lt/eq (for use in OCaml's >> List.sort function, which sorts a list according to the provided comparison >> function). It also provides Date.> >> <https://ocaml.org/p/calendar/3.0.0/doc/CalendarLib/Date/index.html#val-(%3E)>, >> and Date.>= >> <https://ocaml.org/p/calendar/3.0.0/doc/CalendarLib/Date/index.html#val-(%3E=)>, >> etc. Worth noting is that OCaml allows you to do expression-level module >> imports, like Date.(my_t1 > my_t2) to use Date's > function in the >> parenthesized expression without needing to open Date in the entire scope >> ("open" is OCaml's "import") - this could potentially be possible in Elixir >> using a macro? >> Golang: t1.After(t2) <https://pkg.go.dev/time#Time.After>, t1.Before(t2), >> t1.Equal(t2). Non-inclusive (> and <). >> Clojure clj-time library: (after? t1 t2) >> <https://clj-time.github.io/clj-time/doc/clj-time.core.html#var-after.3F>, >> (before? t1 t2) >> <https://clj-time.github.io/clj-time/doc/clj-time.core.html#var-before.3F>, >> and (equal? t1 t2) >> <https://clj-time.github.io/clj-time/doc/clj-time.core.html#var-equal.3F>. >> IMO the argument order is still confusing in these. >> >> >> >> On Sunday, October 30, 2022 at 3:15:14 AM UTC-4 José Valim wrote: >> I am definitely in favor of clearer APIs. >> >> However, it would probably be best to explore how different libraries in >> different languages tackle this. Can you please explore this? In particular, >> I am curious to know if before/after mean "<" and ">" respectively or if >> they mean "<=" and "=>" (I assume the former). And also if some libraries >> feel compelled to expose functions such as "after_or_equal" or if users >> would have to write Date.equal?(date1, date2) or Date.earlier?(date1, >> date2), which would end-up doing the double of conversions. >> >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-co...@googlegroups.com <>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/fcd07389-c6a0-497d-9c09-7f1eacf620c6n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/fcd07389-c6a0-497d-9c09-7f1eacf620c6n%40googlegroups.com?utm_medium=email&utm_source=footer>. >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. > >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-co...@googlegroups.com <>. > >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/e6c55604-c3ea-464c-908c-5a6092f4d8edn%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/e6c55604-c3ea-464c-908c-5a6092f4d8edn%40googlegroups.com?utm_medium=email&utm_source=footer>. > >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. > >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-co...@googlegroups.com <>. > >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2ByT9jA7uqGX0Cyapgfx0AjW%2BU_d4Ai-NQ6vD9UsEb2uQ%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2ByT9jA7uqGX0Cyapgfx0AjW%2BU_d4Ai-NQ6vD9UsEb2uQ%40mail.gmail.com?utm_medium=email&utm_source=footer>. > > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-co...@googlegroups.com <>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/2e821e87-6ee0-4702-b69f-e2616b61b1dd%40app.fastmail.com > > <https://groups.google.com/d/msgid/elixir-lang-core/2e821e87-6ee0-4702-b69f-e2616b61b1dd%40app.fastmail.com?utm_medium=email&utm_source=footer>. > > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-co...@googlegroups.com <>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/7435b979-d0eb-4726-aa65-a94ada53d320n%40googlegroups.com > > <https://groups.google.com/d/msgid/elixir-lang-core/7435b979-d0eb-4726-aa65-a94ada53d320n%40googlegroups.com?utm_medium=email&utm_source=footer>. > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-core+unsubscr...@googlegroups.com > <mailto:elixir-lang-core+unsubscr...@googlegroups.com>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/2ca24f84-0a77-4dcc-8917-83ef18bba16an%40googlegroups.com > > <https://groups.google.com/d/msgid/elixir-lang-core/2ca24f84-0a77-4dcc-8917-83ef18bba16an%40googlegroups.com?utm_medium=email&utm_source=footer>. -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4711C758-EF77-41C6-8EFD-CFA4C09A7474%40achempion.com.