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 endend* 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 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 > 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. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2ca24f84-0a77-4dcc-8917-83ef18bba16an%40googlegroups.com.