using FilePaths
macro iostream_to_lines(methodname)
return quote
function $methodname(io::IOStream)
$methodname(readlines(io))
end
end
end # macro iostream_to_lines
macro path_to_iostream(methodname)
return quote
function $methodname(path::AbstractPath)
isfile(path) && isreadable(path) || error("File $(path) not readable!")
open(path, "r") do io
$methodname(io)
end
end
end
end # macro path_to_iostream
function do_something(lines::Vector{String})
println(first(lines))
end
@iostream_to_lines do_something
@path_to_iostream do_something
I want to generate methods for do_something when the input is an AbstractPath and when the input is an IOStream, finally it falls back to do_something(lines::Vector{String}).
However, this does not work. @iostream_to_lines do_something and @path_to_iostream do_something just generate 2 anonymous functions and they do not add methods to do_something.
I have considered using the @generated macro, but I have 2 difficulties:
I have a lot of do_something-like functions, each of them differs from the others, so I have to write explicitly each do_something-like function for lines as input.
The @generated macro requires the input of do_something to have the same name, e.g., x,
julia> @generated function bar(x)
if x <: Integer
return :(x ^ 2)
else
return :(x)
end
end
bar (generic function with 1 method)
But I have different names for each method: lines::Vector{String}, io::IOStream and path::AbstractPath, they cannot be the same. What should I do?
I tried to write a minimal example. My question is equivalent to
macro mm()
return quote
global a(::Int) = 2
end
end
julia> @mm()
a (generic function with 1 method)
julia> @mm()(2)
2
julia> a
a (generic function with 1 method)
julia> a(2)
2
This works. But it does not work for a multiline function a:
macro mm()
return quote
global function a(::Int)
return 2
end
end
end
julia> @mm()
#1#a (generic function with 1 method)
julia> a
ERROR: UndefVarError: a not defined
sorry but why are you generateing them…you can just… define them?
julia> function do_something(a::AbstractArray)
return a[end]
end
do_something (generic function with 1 method)
julia> function do_something(a::Vector{String})
return a[1]
end
do_something (generic function with 2 methods)
julia> do_something(["hi" "there"; "good" "day"])
"day"
julia> do_something(["hi", "good", "day"])
"hi"
function $methodname(path::AbstractPath)
isfile(path) && isreadable(path) || error("File $(path) not readable!")
open(path, "r") do io
$methodname(io)
end
end
and
function $methodname(io::IOStream)
$methodname(readlines(io))
end
repeatedly on more functions like do_something(lines::Vector{String}), I want to reuse the 2 paradigms. The only differences between each of these functions are just the methodname.
You need to escape the input (see the manual on “macro hygiene”).
julia> macro iostream_to_lines(methodname)
return quote
function $methodname(io::IOStream)
$methodname(readlines(io))
end
end
end # macro iostream_to_lines
@iostream_to_lines (macro with 1 method)
julia> @macroexpand @iostream_to_lines do_something
quote
#= REPL[14]:3 =#
function #11#do_something(#12#io::Main.IOStream) # <------- mangled function name
#= REPL[14]:4 =#
#11#do_something((Main.readlines)(#12#io))
end
end
julia> macro iostream_to_lines(methodname)
return quote
function $(esc(methodname))(io::IOStream)
$(esc(methodname))(readlines(io))
end
end
end # macro iostream_to_lines
@iostream_to_lines (macro with 1 method)
julia> @macroexpand @iostream_to_lines do_something
quote
#= REPL[16]:3 =#
function do_something(#13#io::Main.IOStream) # <----------- the name you want
#= REPL[16]:4 =#
do_something((Main.readlines)(#13#io))
end
end