# Determine possibility to sort via hasmethod(isless, (T,T) for AbstractVector{T}

**URL:** <https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291>\
**Category:** General Usage\
**Created:** [August 30, 2018, 6:53am UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291 "2018-08-30T06:53:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [August 30, 2018, 6:53am UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/1 "2018-08-30T06:53:49Z")

</div>

I want to decide if an AbstractVector is sorted to adequately choose the code path for my algorithm. For this I first need to know if it is safe to call issorted(A). Are there faster/better/more robust ways than doing it like this:

```julia
issafelysorted(A::AbstractVector{T}) where T = isconcretetype(T) && 
    hasmethod(isless, (T,T)) &&
    (issorted(A) || issorted(A, rev = true))
# or
issafelysortedTry(x::AbstractVector{T}) where T = 
    try issorted(x) || issorted(x, rev = true) catch e false end

```

Both are quite expensive to call in case isless is not defined, as can be seen here:

```julia
julia> using BenchmarkTools

julia> struct Foo x end

julia> b = [Foo(4), Foo(6)]
2-element Array{Foo,1}:
 Foo(4)
 Foo(6)

julia> @btime issafelysorted($b)

  6.412 μs (4 allocations: 176 bytes)
false

julia> @btime issafelysortedTry($b)
  55.576 μs (5 allocations: 208 bytes)
false

julia> Base.isless(x::Foo,y::Foo) = x.x < y.x

julia> @btime issafelysorted($b)
  349.260 ns (1 allocation: 32 bytes)
true

julia> @btime issafelysortedTry($b)
  36.243 ns (0 allocations: 0 bytes)
true
```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 30, 2018, 7:29am UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/2 "2018-08-30T07:29:04Z")

</div>

I am confused: if you want to `sort`, wouldn’t you need `isless` anyway? So I would just assume that it exists and get a `MethodError` early if it doesn’t.

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [August 30, 2018, 7:36am UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/3 "2018-08-30T07:36:48Z")

</div>

For this algorithm the AbstractVector doesn’t necessarily needs to be sortable, but if it is sortable and sorted I can follow a faster code path.

```julia
if sortable(A) && issorted(A)
# fast code path
else
# slow code path
end

```

---

<div class="post-metadata">

**Author:** ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)\
**Post date:** [August 30, 2018, 11:41am UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/4 "2018-08-30T11:41:25Z")

</div>

If you don’t need the `issafelysorted` function to be dynamic, you could determine this at compile time with a generated function.

Maybe something like this?

```julia
@generated function issafelysorted(A::AbstractVector{T}) where T
    if isconcretetype(T) && hasmethod(isless, Tuple{T,T})
        return :(issorted(A) || issorted(A, rev=true))
    else
        return :false
    end
end

```

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [August 30, 2018, 1:56pm UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/5 "2018-08-30T13:56:16Z")

</div>

Thx, I might be misreading something but apparently this is now allowed (manual - metaprogramming):

> Generated functions must not _mutate_ or _observe_ any non-constant global state (including, for example, IO, locks, non-local dictionaries, or using `hasmethod` ).

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [August 30, 2018, 3:31pm UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/6 "2018-08-30T15:31:27Z")

</div>

You’re correct. It’s not allowed, although it will _sometimes_ work (the fact that it only sometimes works is exactly why it’s not allowed).

Julia makes no guarantees about when, or how often, the `@generated` function body will be called. By putting a `hasmethod()` call in there, you’re fixing the result based on whether that method happened to exist when the `@generated` function body was called. That can give inconsistent behavior if, for example, that generator happens to be run before the relevant `isless` method is defined.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [August 31, 2018, 10:28pm UTC](https://discourse.julialang.org/t/determine-possibility-to-sort-via-hasmethod-isless-t-t-for-abstractvector-t/14291/7 "2018-08-31T22:28:07Z")

</div>

I was asking exactly the same question a few weeks ago 🙂

> [@Can I use hasmethod inside @generated function?](https://discourse.julialang.org/t/can-i-use-hasmethod-inside-generated-function/13645):
>
> I thought the answer was no, since hasmethod is not pure. But unless I try very hard to break it (see struct B example below) I cannot invoke any suspicious bugs. From the example I wrote, it seems that using hasmethod inside @generated function is OK as long as the method checked by hasmethod is already defined before the first invocation of the method. Is it correct? Are there any other pitfalls? Am I relying on some implementation details of julia which can change in the future? To avoi…
