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