Hi,
I would like to be able to use the > and >> characters as valid kwarg names. Example
julia> grd2xyz(G, >="lixo.xyz")
ERROR: syntax: ">=" is not a unary operator
The reason why it fails seems understandable, but I managed to make it work with the pipe operator.
julia> grd2xyz(G, |>="lixo.xyz")
Let me say that the parsing of the above is done by this line
if (haskey(d, :|>)) cmd = string(cmd, " > ", d[:|>]) end
So, neither > nor |> are unary operators but I can use |> as kwarg name but not >.
All would be good if I didnβt want to implement also the >> kwarg for the shell append to file operator. And here nothing that I tried works. |>> seemed the logical one, but again
julia> grd2xyz(G, |>>="lixo.xyz")
ERROR: syntax: "|>" is not a unary operator
julia> f(x; > = 1) = >
f (generic function with 1 method)
julia> f(1, > = 2)
2
Just be aware that you canβt use the > operator in the function f, which seems like a problem to me (unless you go the kwargs Dict route, but thatβs more suited for handling an unknown number of keywords which may contain some you donβt want to/canβt handle).
The reason your original didnβt work is because of operator precedence - julia tries to evaluate the expression >="lixo.xyz" during which it doesnβt find a second argument to >=, since thatβs a binary operator. Assignments have the lowest precedence, which is why you have to write it this way with the space.
In general though, itβs adviced not to do that. Is there a special reason you want to have that character as an argument?
Thanks, and yes, I see the risk of it.
The reason why I want to have those characters is be cause they exactly match what one would do in the shell. To explain better, on the shell this (GMT) command
grd2xyz G > lixo.xyz
Takes a grid (G) and converts it to a Mx3 file with x,y,z values. The closest I can get from the GMT Julia wrapper is to do
grd2xyz(G, > ="lixo.xyz")
Sure that can impose another syntax like
grd2xyz(G, redirect="lixo.xyz")
but then for appending to a previously existing file I would need something like
grd2xyz(G, redirect_append="lixo.xyz")
β¦ humm, but now that Iβm looking at it maybe it doesnβt look so bad.
I definitely think having clear names for keyword arguments is more julian - after all, if someone else is going to use that function at some point, they are bound to fall into the same pitfall you did with the operator precedence. Moreover, having a clear to read name helps reduce ambiguity - someone not used to Bash or some other Shell might not know about output redirection using > there. For them, having > as a keyword is surely going to feel alien and unintuitive.
You could also take a look at how open does it with itβs mode argument. As far as I know, having a mode is pretty much universal when it comes to IO (think C).
help?> open
# <snip>
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
open(filename::AbstractString, [mode::AbstractString]) -> IOStream
Alternate syntax for open, where a string-based mode specifier is used instead of the five booleans. The values of mode correspond to those from fopen(3) or Perl open, and are
equivalent to setting the following boolean groups:
Mode Description Keywords
ββββ βββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
r read none
w write, create, truncate write = true
a write, create, append append = true
r+ read, write read = true, write = true
w+ read, write, create, truncate truncate = true, read = true
a+ read, write, create, append append = true, read = true
# snip
Thanks again, but the opening mode is not really an alternative here. The > or redirect serves as an alternative output (to a disk file) instead of returning the result of the operation into a julia variable. e.g
D = grd2xyz(G);
will return a Mx3 matrix (wrapped into a GMTdataset) into the D Julia variable.
You can return & write to file independently - a mode keyword with default being return_only or something like that would accomplish that. Different modes can, in addition to the return, also write to the file specified. I just gave open as an example since that has a mode keyword used to distinguish between behaviour.
That is actually a good starting point for using macros. Since you already coded most of the functionality, now you can just create convenient macros that will rewritte expressions that resembles GMT syntax to your function calls already written.
It is never to late to rewrite code.
(It is why I prefer coding to wood working, or sewing, or welding or β¦)
Anyway, for next time you want to do weird syntax.
Here is how to use a cmd macro (string macros are basically the same)
to put a DSL into julia.
Lets say you have a function, that is fairly standard julia code.
function grd2xyz(G, mode=nothing, file=nothing)
F = G*G # or what wever operation you need to do
if mode == ">>"
println("appending $F to $file")
elseif mode == ">"
println("overwriting $F to $file")
end
return F
end
Here is the macro to wrap a DSL around that function
I may be wrong ofc, but the issue is that I already coded all the machinery needed to rewrite the expressions into what the syntax that GMT lib expects. And itβs not all strings. For example both of this are valid Julia syntax (to define a bounding box) limits="0/10/0/10" or limits=[0 10 0 10] or limits=G where G is a grid and extra code will take charge to extract the BB from the gridβs header.
Sure (when one get tired of old bugs and need new ones )
Iβll keep a trace on this for next time I need something of this kind. Thatβs the beauty of this forum.
BTW here is the grd2xyz. A relatively small one but there are others with tons of options.
I scanned the GMT and GMT.jl projects. Powerful stuff! Thank you for developing a Julia API for GMT.
According to the documentation you support βMonoliticβ and βBy Moduleβ modes. Your original question was about
julia> grd2xyz(G, >="lixo.xyz")
That seems to be βBy Moduleβ mode and for that you already translate one letter GMT options to more readable Julia keyword arguments. In that context I see nothing wrong with translating the β>β operator to keyword argument redirect=.
With respect to your βMonoliticβ mode, consider adding (as a future enhancement) a string macro (or command macro) that translates any GMT shell command to the API you already have.
For example macro GMT_str could translate
I ended up with write=... and write_append because redirect calls to the shell > concept and as mentioned above, there are people that donβt know much about that.
As for the βMonolithicβ mode, well thatβs how things work. I mean, thatβs what the GMT lib actually understands. The βBy modulesβ was a large effort to come up with something less cryptic but under the hood all is translated to the βMonolithicβ way, which has tight rules on the order of (variable) input data. Itβs because of these tight rules that Iβm afraid a macro language would be hard to implement. But who knows.