Yea I agree with you that multiple dispatch can achieve the same thing and much better (such a lovely feature).
But there is a problem - consider: type Dequeue ... end type Last end type First end getindex(d::Dequeue, ::Last) = last(d) getindex(d::Dequeue, ::First) = first(d) pop!(d::Dequeue, ::Last) = pop!(d) # removes and returns last element pop!(d::Dequeue, ::First) = shift!(d) # removes and returns first element pop!(d::Dequeue, index::Int) = splice!(d) # removes and returns element at index x - My types Last / First can clash with types I have defined elsewhere. - I want to do [ dequeue[Last] ] instead of [ dequeue[Last() ] How can I go around these ? Dne čtvrtek 26. května 2016 21:23:32 UTC+2 Matt Bauman napsal(a): > > So, if I understand correctly, the problem you're trying to solve is that > A[end] lowers to getindex(A, endof(A)), but you want to know that the index > is the last one since you can implement a more efficient algorithm in that > case. > > Making getindex a macro won't solve this problem, so lets set aside that > discussion. But there may be a solution for you here. You can try using a > special index type that specifically refers to the number of indices from > the end. > > immutable BackwardsIndex <: Integer > i::Int > end > > Now simply add `getindex(::YourType, ::BackwardsIndex)` method that > traverses the dequeue backwards. `x[BackwardsIndex(1)]` then refers to > your last element with O(1) complexity. That's pretty verbose, but here's > what you can try: make `endof(::YourType) = BackwardsIndex(1)`. Now > `A[end]` is O(1) complexity. This won't work for AbstractArray subtypes, > but I think it should work for other custom indexable types. > > You can even add primitive arithmetic to the BackwardsIndex type to > support things like `A[end-1]`, but anything more than that becomes > complicated fast. What's `x[end÷2]`? Or worse: `x[rand(2:end-1)]`? These > are the same challenges that a syntax-level change would rapidly run into. > > Matt > > On Thursday, May 26, 2016 at 2:45:34 PM UTC-4, Stefan Karpinski wrote: >> >> The difference is that a symbol is a value but `end` is not a value. If >> you can write >> >> v[:foo] >> >> >> then you should also be able to do this: >> >> x = :foo >> v[x] >> >> >> This precludes doing the lookup at compile time – except as an >> optimization. That argument doesn't apply to `end` since the `end` keyword >> is purely syntactic – trying to assign `end` to a variable is just a syntax >> error: >> >> x = end >> >> v[x] >> >> >> Lowering things to macro calls is sometimes effective – we do this for >> non-standard string literals, for example – but it should be done as >> sparingly. In this case, the only thing that you're going to accomplish >> with this approach is to make a feature that's thoroughly broken. For >> example, by having v[:foo] do one thing while `x = :foo; v[x]` does >> something completely different. >> >> On Thu, May 26, 2016 at 2:31 PM, Ford Ox <[email protected]> wrote: >> >>> >>> >>> Dne čtvrtek 26. května 2016 18:03:50 UTC+2 Yichao Yu napsal(a): >>>> >>>> > Because it is done at compile time, where you can even decide to call >>>> > completely different function. See >>>> > dequeue = ..... >>>> > dequeue[:first] # is replaced with different function than dequeue[1] >>>> > dequeue[:last] # is replaced with different function than >>>> dequeue[end] ( >>>> > O(1) vs O(n) ) >>>> >>>> I don't see what you mean by compile time. You cannot dispatch on the >>>> symbol at compile time. If you use syntax level rewrite, there's no >>>> point of using symbol either. >>>> >>> >>> What do you mean by syntax level. Why there is no point for using symbol >>> if that's the case? >>> >>> >>>> >>>> > >>>> > Because you can define your own syntax. The :middle was just stupid >>>> example >>>> > to show you, that you can decide on your own symbol based on >>>> collection you >>>> > are working with ( say there is collection which when accessing >>>> middle has >>>> > different complexity than accessing other elements). >>>> >>>> You can easily do this by defining your own token. Misusing the symbol >>>> syntax isn't the right way to go. >>>> >>> >>> Yeah, I also feel that using symbol is not the right approach, but I >>> couldn't think about any other simpler way of doing that. >>> Can you show me what do you mean by token? >>> >>> >>>> >>>> > >>>> > Of course you can do arithmetics with this approach. >>>> >>>> No you can't. Not in a way that you can overload it for different types >>>> anyway. >>>> >>>> >> Which is what make the way you propose unsatisfying. >>>> >> >>>> > >>>> > Are you talking about [ FIRST = :first ]? >>>> > If so, I could argue about this since you can't also do [ LAST = end >>>> ] >>>> > The only difference is that [ LAST = end ] throws error at compile >>>> time. >>>> >>>> The difference is that `end` is a keyword. And symbol literal is not. >>>> >>> Which is intended and its fine. >>> The problem is that user won't know, what symbols should he use, unless >>> he checks the docs, which is not nice. >>> >> >>
