# How to generate methods based on different types of the parameter?

**URL:** https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530
**Category:** General Usage
**Tags:** question
**Created:** [July 19, 2019, 4:35am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530 "2019-07-19T04:35:28Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)
#### Post date: [July 19, 2019, 4:35am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530/1 "2019-07-19T04:35:28Z")

</div>

For example, I have the following code

```julia
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:

1. 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.
2. The `@generated` macro requires the input of `do_something` to have the same name, e.g., `x`,

```julia
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?

---

<div class="post-metadata">

### Author: ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)
#### Post date: [July 19, 2019, 7:52am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530/2 "2019-07-19T07:52:12Z")

</div>

I tried to write a minimal example. My question is equivalent to

```julia
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`:

```julia
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

```

Why?

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [July 19, 2019, 9:26am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530/3 "2019-07-19T09:26:45Z")

</div>

sorry but why are you `generate`ing them…you can just… define them?

```julia
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"

```

---

<div class="post-metadata">

### Author: ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)
#### Post date: [July 19, 2019, 9:36am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530/4 "2019-07-19T09:36:24Z")

</div>

Hi, I am using

```julia
function $methodname(path::AbstractPath)
    isfile(path) && isreadable(path) || error("File $(path) not readable!")
    open(path, "r") do io
        $methodname(io)
    end
end

```

and

```julia
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`.

> [@singularitti](#):
>
> 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.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [July 19, 2019, 9:43am UTC](https://discourse.julialang.org/t/how-to-generate-methods-based-on-different-types-of-the-parameter/26530/5 "2019-07-19T09:43:47Z")

</div>

You need to escape the input (see the manual on “macro hygiene”).

```julia
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

```
