Hi everyone, I’m trying to get used to programming with custom types and am in the following situation:
Suppose I want to write a Program that calls an API, and there are different types of calls.
First, I made a struct representing the call to the API:
struct APIRequest{T}
type::T
name::AbstractString
query::AbstractString
fields::NTuple
end
Now the difference (for now) between various types of calls is only the base URL. So my first thought was something like:
struct CallType1
url::AbstractString
## Where the url is fixed, and should not have to be provided.
end
struct CallType2
url::AbstractString
## Where the url is fixed, and should not have to be provided.
end
Is something like this considered bad design? I was trying to make use of multiple dispatch, because later functions may be different depending on the type of request.
This may or may not be abuse of dispatch depending on other factors.
I can think of some good reasons to use multiple dispatch.
You want to improve the run times of the function from the second time to the last time it is called with arguments of the same type, and can sacrifice the performance at each first call with arguments of different types (increase compilation times and the space in the memory the code takes). If your function will in the end call some kind of REST API, this would not make much sense, because the code for each function will be about the same (calling a function that make an HTTP request) and the internet latency will be dominant here anyway.
You want people to be able to externally extend your code. So people can create their own type of APIRequest, that may need some special handling (something that cannot be achieved just by having different values inside it). Basically, you use multiple dispatch to expose a possible future switch/if-elseif-else structure that will be inside your code and handle the differences depending on the requested URL. This seem more like your case. But you do not need to give others the power to extend this function of yours, then just dealing with this internally is ok. You may even use multiple dispatch, but in a non-exported inner use function just to do what is different for each request.
If you take the decision to use multiple dispatch, and you want to dispatch in the URL, I would not make such CallType structs, but instead just make the URL a Symbol and pass it as a type parameter of APIRequest.
struct APIRequest{URL}
# there is no need of an URL field
# you can extract the URL from the type
name::AbstractString
query::AbstractString
fields::NTuple
end
function myprint(req :: APIRequest{URL}) where {URL}
println(URL)
end
myprint(APIRequest{Symbol("https://myurl.com/request")}("name", "query", (1, 2, 3)))