Reputation: 33
What is the best pattern to create literal types in Julia?
In Typescript, you can make types out of string literals:
type command = "start" | "end" | "pause";
In Julia, this would allow you to use multiple-dispatch with string arguments, making it easy to extend cases.
An example of this would look like
function process(::"start")
initialize()
do_something()
...
end
function process(::"end")
teardown()
...
end
function process(::"pause")
temporary_pause()
...
end
Currently, I am using a workaround similar to this
struct CommandType{T}
end
CommandType(s::AbstractString) = CommandType{Symbol(s)}()
macro CommandType_str(s)
return CommandType{Symbol(s)}
end
function process(t::CommandType"start")
...
end
function process(t::CommandType"stop")
...
end
function process(t::CommandType"pause")
...
end
process(command::String) = process(CommandType(command))
# Usage
process("start")
Is there a more succinct pattern I can use? Is it possible that literal types will be added to Julia in the near future?
Upvotes: 3
Views: 351
Reputation: 2824
The closest thing i managed to get without going crazy and without polluting the scope of hoisted symbols is:
module Extraction
@enum Type log_stats_by_author commits_by_author
end
function extract_git_stats(extraction_type::Extraction.Type)
...
end
extract_git_stats(Extraction.commits_by_author)
This also works with intellisense in Julia's vscode extension, solutions using Symbol/Val won't provide any autocompletion:
Upvotes: 0
Reputation:
I would take another approach to your problem, don't rely on string or symbols to determine which function to use, instead write functions that have clear names.
For example, your function is named process()
and takes a start
command. What I'm I processing? Do I do something with that command in the function?
Instead what if I wrote:
function start_service(# pass required arguments)
...
end
Sounds better, I know what I'm starting and the necessary arguments, if any, would make sense.
Later on, I decide I need to write data to a file, I now have to update the Command
, perhaps, write
?
function process(::CommandType"write",path::AbstractString,data)
# What is being written? Error log? Data?
end
It would be cleaner to write:
write_data_to(path::AbstractString)
Upvotes: 1
Reputation: 69949
As far as I know the current practice is essentially what you have developed. To be concrete it is to use Val
with Symbol
argument. So your function signature would be e.g. process(::Val{:start})
and you would call it with process(Val(:start))
(of course you could use a utility function or macro to generate Val(:start)
from a string as in your code if you wanted)
Upvotes: 4