There is no difference if you don't use the argument, and yes, for the compiler this should be trivial.
You can use _ as an actual "discard argument" though, and the parser will prevent you from using it:
julia> f(_) = _ + 1
ERROR: syntax: all-underscore identifier used as rvalue around REPL[9]:1
That's useful in some situations:
julia> _, _, z = (1,2,3)
(1, 2, 3)
julia> z
3
julia> _
ERROR: all-underscore identifier used as rvalue
while
julia> x, x, z = (1,2,3)
(1, 2, 3)
julia> x
2
is slightly confusing.
More technicalities
An unused argument is preseved in IR, though:
julia> one(::String) = return 1
one (generic function with 1 method)
julia> one2(s::String) = return 1
one2 (generic function with 1 method)
julia> ir = @code_lowered one("sdf")
CodeInfo(
1 ─ return 1
)
julia> ir.slotnames
2-element Array{Symbol,1}:
Symbol("#self#")
Symbol("#unused#")
julia> ir2 = @code_lowered one2("sdf")
CodeInfo(
1 ─ return 1
)
julia> ir2.slotnames
2-element Array{Symbol,1}:
Symbol("#self#")
:s
If you ever care about slot names. I can't imagine how this would change further compilation, but it can be a corner case in metaprogramming.