Getting the last element of an iterator

Didn’t get applicable much more robust over the time? Because that tells whether there is last, after all.

Types seem to be inferred, but comparing these two outputs:

mylast(a) = applicable(lastindex, a) ? a[end] : 0;
@code_native last([1,2,3])
@code_native mylast([1,2,3])

the second case adds the following operations:

	pushq	%rbx
	subq	$24, %rsp
	movq	%rdi, %rbx
	movabsq	$jl_system_image_data, %rax
	movq	%rax, -24(%rbp)
	movq	%rdi, -16(%rbp)
	movabsq	$jl_f_applicable, %rax
	leaq	-24(%rbp), %rsi
	xorl	%edi, %edi
	movl	$2, %edx
	callq	*%rax
	cmpb	$0, (%rax)
	je	L99

It seems too much for something that can often find itself in hot loops…

You could make the decision at compile time

lastarg(_,x) = x
@generated mylast(a) = hasmethod(lastindex, (a,)) ? :(last(a)) : :(foldl(lastarg, a));

That’s problematic, because mylast will not be updated if lastindex is redefined later. GitHub - oxinabox/Tricks.jl: Cunning tricks though the julia compiler internals can do this with backedges, but this should generally be avoided, since it can cause excessive invalidations. In this particular case, you can probably just use dispatch for this.

Indeed the documentation says explicitely:

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

@simeonschaub how would you use dispatch here? Currently last is defined as

last(a) = a[end]

I could define this method only for AbstractArray, but that would not be backward compatible: the method would no longer be called for types that implement getindex and lastindex without deriving from AbstractArray

Incidentally I actually used last for some kind of fixed point iteration here and defining it without type constraint seemingly broke my Atom IDE :slight_smile: