[julia-users] Macros inside functions
Hi Is it possible to use macros inside o functions in Julia if they are expanded at compile time as the manual says? I've been playing with a toy type: type MeltingTemperature value::Int end myvar = MeltingTemperature(56) and say I want to make a function that write it out as an XML string: "56 Now I want to make a function that constructs that string by 1). Adding the open tag 2). Checking the temperature is not nothing and if it is not, including it in the string. 3). add the closing tag. I figured step 2 would be a good candidate for a macro for a larger type as checking each value is not nothing would be tedious. So: macro INN(string, value) value != nothing ? "$string$value" : "$string" end function writePhyXML(x::MeltingTemperature) outstring = "" outstring = @INN outstring x.value; outstring = "$(outstring)" outstring end I figured the macro would be expanded and the function definition would become: function writePhyXML(x::MeltingTemperature) outstring = "" outstring = x.value != nothing ? "$outstring$x.value" : "$outstring" outstring = "$(outstring)" outstring end But results in "outstringx.value" Is it possible to do this with macro's? I had presumed it is. (I know it's possible by just using a sub function, but I wanted to see how to try and use macros to generate code for function definitions if possible.) Thanks, Ben.
Re: [julia-users] Macros inside functions
disclaimer: I would use a function, not a macro for this purpose: INN( outstring, value ) = value !== nothing ? "$outstring$value" : outstring INN(outstring, x.value) it is simpler, and gives up nothing in exchange for actually being readable and versatile but assuming you had a more interesting use case: when you expand the macro as written, the result is: "$string$value", with string=:outstring and value=:(x.value), exactly as you specified: "outstringx.value" but you want the string before interpolation (note that I'm switching to the functional form of string interpolation because it is easier to read in macro form), so we need this complicated thing to make a macro that is actually just a function: macro INN(str, val) :( v = $(esc(val)); s = $(esc(str)); v != nothing ? string(v, s) : s ) end but the better way to write that is: INN( outstring, value ) = value !== nothing ? "$outstring$value" : outstring macro INN(str, val) :( INN($(esc(str)), $(esc(val))) ) end why is this better? it's easier to read, write, and debug (also, because it makes it obvious that you should not be using a macro for this) finally, there's the even cleaner options: outstring = "$(x.value!==nothing?x.value:"")" or, using multiple dispatch -- my favorite option (excellent API for future extensibility): mystr(::Nothing) = "" mystr(x) = x outstring = "$(mystr(x))" note that since in your type, you have value::Int, so value will always be an Int, never another type (like nothing), so it's a pointless test final note, string concatenation using $ or * or string (all of which are exactly equivalent) is going to be slow compared to making an IOBuffer, printing / writing / or showing all of your text to the buffer, then calling takebuf_string(iobuf) at then end On Thu, Apr 17, 2014 at 11:38 PM, Ben Ward wrote: > Hi Is it possible to use macros inside o functions in Julia if they are > expanded at compile time as the manual says? I've been playing with a toy > type: > > type MeltingTemperature > value::Int > end > > > > > myvar = MeltingTemperature(56) > > > and say I want to make a function that write it out as an XML string: > "56 > > Now I want to make a function that constructs that string by 1). Adding the > open tag 2). Checking the temperature is not nothing and if it is not, > including it in the string. 3). add the closing tag. > > I figured step 2 would be a good candidate for a macro for a larger type as > checking each value is not nothing would be tedious. So: > > macro INN(string, value) > value != nothing ? "$string$value" : "$string" > end > > > function writePhyXML(x::MeltingTemperature) > outstring = "" > outstring = @INN outstring x.value; > outstring = "$(outstring)" > outstring > end > > > I figured the macro would be expanded and the function definition would > become: > > function writePhyXML(x::MeltingTemperature) > outstring = "" > outstring = x.value != nothing ? "$outstring$x.value" : "$outstring" > outstring = "$(outstring)" > outstring > end > > > But results in "outstringx.value" > > Is it possible to do this with macro's? I had presumed it is. > > (I know it's possible by just using a sub function, but I wanted to see how > to try and use macros to generate code for function definitions if > possible.) > > Thanks, > Ben.
Re: [julia-users] Macros inside functions
Thanks, Jameson, I should say in this case it is obvious the function would be better and I agree, this was a case I made myself to see if it could be done. The reason being, I'm writing a type, the composition of which could be extended by the user to contain other information (I'm working with a data format and file format(s) for phylogenetic data which is often non standard). So I made the base type extendible, and now I'm trying to get the stuff that reads or writes to file to be extendible. I'm currently working on the writing stuff to file, and what I've done got is a function which will write the data to file, including the extra user extended data, as long as the user has provided a method for representing it as a string, and so I thought providing some macro's to make defining such methods more quick and painless to write for the user, but perhaps providing a set of sub-functions would be better. Hence the INN macro, so you don't have to write lines checking it's not nothing every time (which I know shouldn't happen, but again, this is a bit of a contrived case to try and see if it could/should be done this way. I also had an idea for writing a macro which generated the entire function for the user given some basic information, but baby steps first. Strikes me a lot of times I figure a macro would be good for something, a function can do the same job. Best, Ben. On Friday, April 18, 2014 6:38:14 AM UTC+1, Jameson wrote: > > disclaimer: I would use a function, not a macro for this purpose: > INN( outstring, value ) = value !== nothing ? "$outstring$value" : > outstring > INN(outstring, x.value) > > it is simpler, and gives up nothing in exchange for actually being > readable and versatile > > but assuming you had a more interesting use case: when you expand the > macro as written, the result is: > "$string$value", with string=:outstring and value=:(x.value), exactly > as you specified: "outstringx.value" > > but you want the string before interpolation (note that I'm switching > to the functional form of string interpolation because it is easier to > read in macro form), so we need this complicated thing to make a macro > that is actually just a function: > macro INN(str, val) > :( v = $(esc(val)); s = $(esc(str)); v != nothing ? string(v, s) : s ) > end > > but the better way to write that is: > INN( outstring, value ) = value !== nothing ? "$outstring$value" : > outstring > macro INN(str, val) > :( INN($(esc(str)), $(esc(val))) ) > end > > why is this better? it's easier to read, write, and debug (also, > because it makes it obvious that you should not be using a macro for > this) > > finally, there's the even cleaner options: > outstring = "$(x.value!==nothing?x.value:"")" > > or, using multiple dispatch -- my favorite option (excellent API for > future extensibility): > mystr(::Nothing) = "" > mystr(x) = x > outstring = "$(mystr(x))" > > note that since in your type, you have value::Int, so value will > always be an Int, never another type (like nothing), so it's a > pointless test > > final note, string concatenation using $ or * or string (all of which > are exactly equivalent) is going to be slow compared to making an > IOBuffer, printing / writing / or showing all of your text to the > buffer, then calling takebuf_string(iobuf) at then end > > On Thu, Apr 17, 2014 at 11:38 PM, Ben Ward > > > wrote: > > Hi Is it possible to use macros inside o functions in Julia if they are > > expanded at compile time as the manual says? I've been playing with a > toy > > type: > > > > type MeltingTemperature > > value::Int > > end > > > > > > > > > > myvar = MeltingTemperature(56) > > > > > > and say I want to make a function that write it out as an XML string: > > "56 > > > > Now I want to make a function that constructs that string by 1). Adding > the > > open tag 2). Checking the temperature is not nothing and if it is not, > > including it in the string. 3). add the closing tag. > > > > I figured step 2 would be a good candidate for a macro for a larger type > as > > checking each value is not nothing would be tedious. So: > > > > macro INN(string, value) > > value != nothing ? "$string$value" : "$string" > > end > > > > > > function writePhyXML(x::MeltingTemperature) > > outstring = "" > > outstring = @INN outstring x.value; > > outstring = "$(outstring)" > > outstring > > end > > > > > > I figured the macro would be expanded and the function definition would > > become: > > > > function writePhyXML(x::MeltingTemperature) > > outstring = "" > > outstring = x.value != nothing ? "$outstring$x.value" : "$outstring" > > outstring = "$(outstring)" > > outstring > > end > > > > > > But results in "outstringx.value" > > > > Is it possible to do this with macro's? I had presumed it is. > > > > (I know it's possible by just using a sub function, but
Re: [julia-users] Macros inside functions
Thinking about it some more, and how you advise to use multiple dispatch to write these things out - is it possible to use multiple dispatch to read in things similarly? Because the thing you are reading in is to become the types you base the dispatch of the method on, so how could this apply to reading in types when the instances of the types are not extant yet? Maybe if you supply a empty instance of the type you want to read in for the dispatch? e.g. inmystr(x::file, y::MeltingPoint) = # how to extract info from text here. So I want to reading in MeltingPoint data from a file, and want to use the inmystr method that applies based on the function signature, yet I have no MeltingPoint types currently, because I'm trying to read them in, instead of having the object and writing it out. I know in C++ when trying to catch multiple different types of possible throws, you can define empty types to act as error types, I wonder if such a tactic here is applicable. Best, Ben. On Friday, April 18, 2014 6:38:14 AM UTC+1, Jameson wrote: > > disclaimer: I would use a function, not a macro for this purpose: > INN( outstring, value ) = value !== nothing ? "$outstring$value" : > outstring > INN(outstring, x.value) > > it is simpler, and gives up nothing in exchange for actually being > readable and versatile > > but assuming you had a more interesting use case: when you expand the > macro as written, the result is: > "$string$value", with string=:outstring and value=:(x.value), exactly > as you specified: "outstringx.value" > > but you want the string before interpolation (note that I'm switching > to the functional form of string interpolation because it is easier to > read in macro form), so we need this complicated thing to make a macro > that is actually just a function: > macro INN(str, val) > :( v = $(esc(val)); s = $(esc(str)); v != nothing ? string(v, s) : s ) > end > > but the better way to write that is: > INN( outstring, value ) = value !== nothing ? "$outstring$value" : > outstring > macro INN(str, val) > :( INN($(esc(str)), $(esc(val))) ) > end > > why is this better? it's easier to read, write, and debug (also, > because it makes it obvious that you should not be using a macro for > this) > > finally, there's the even cleaner options: > outstring = "$(x.value!==nothing?x.value:"")" > > or, using multiple dispatch -- my favorite option (excellent API for > future extensibility): > mystr(::Nothing) = "" > mystr(x) = x > outstring = "$(mystr(x))" > > note that since in your type, you have value::Int, so value will > always be an Int, never another type (like nothing), so it's a > pointless test > > final note, string concatenation using $ or * or string (all of which > are exactly equivalent) is going to be slow compared to making an > IOBuffer, printing / writing / or showing all of your text to the > buffer, then calling takebuf_string(iobuf) at then end > > On Thu, Apr 17, 2014 at 11:38 PM, Ben Ward > > > wrote: > > Hi Is it possible to use macros inside o functions in Julia if they are > > expanded at compile time as the manual says? I've been playing with a > toy > > type: > > > > type MeltingTemperature > > value::Int > > end > > > > > > > > > > myvar = MeltingTemperature(56) > > > > > > and say I want to make a function that write it out as an XML string: > > "56 > > > > Now I want to make a function that constructs that string by 1). Adding > the > > open tag 2). Checking the temperature is not nothing and if it is not, > > including it in the string. 3). add the closing tag. > > > > I figured step 2 would be a good candidate for a macro for a larger type > as > > checking each value is not nothing would be tedious. So: > > > > macro INN(string, value) > > value != nothing ? "$string$value" : "$string" > > end > > > > > > function writePhyXML(x::MeltingTemperature) > > outstring = "" > > outstring = @INN outstring x.value; > > outstring = "$(outstring)" > > outstring > > end > > > > > > I figured the macro would be expanded and the function definition would > > become: > > > > function writePhyXML(x::MeltingTemperature) > > outstring = "" > > outstring = x.value != nothing ? "$outstring$x.value" : "$outstring" > > outstring = "$(outstring)" > > outstring > > end > > > > > > But results in "outstringx.value" > > > > Is it possible to do this with macro's? I had presumed it is. > > > > (I know it's possible by just using a sub function, but I wanted to see > how > > to try and use macros to generate code for function definitions if > > possible.) > > > > Thanks, > > Ben. >
Re: [julia-users] Macros inside functions
Every type has a corresponding singleton value that is the type itself, and can be dispatched on: inmystr(x::file, ::MeltingPoint) = #function new_melting_point_thing = inmystr(f, MeltingPoint) This is the technique used by the conversions mechanism: http://julia.readthedocs.org/en/latest/manual/conversion-and-promotion/#man-conversion On Friday, April 18, 2014 6:08:35 AM UTC-5, Ben Ward wrote: > > Thinking about it some more, and how you advise to use multiple dispatch > to write these things out - is it possible to use multiple dispatch to read > in things similarly? Because the thing you are reading in is to become the > types you base the dispatch of the method on, so how could this apply to > reading in types when the instances of the types are not extant yet? Maybe > if you supply a empty instance of the type you want to read in for the > dispatch? e.g. > > inmystr(x::file, y::MeltingPoint) = # how to extract info from text here. > > So I want to reading in MeltingPoint data from a file, and want to use the > inmystr method that applies based on the function signature, yet I have no > MeltingPoint types currently, because I'm trying to read them in, instead > of having the object and writing it out. I know in C++ when trying to catch > multiple different types of possible throws, you can define empty types to > act as error types, I wonder if such a tactic here is applicable. > > Best, > Ben. > > On Friday, April 18, 2014 6:38:14 AM UTC+1, Jameson wrote: >> >> disclaimer: I would use a function, not a macro for this purpose: >> INN( outstring, value ) = value !== nothing ? "$outstring$value" : >> outstring >> INN(outstring, x.value) >> >> it is simpler, and gives up nothing in exchange for actually being >> readable and versatile >> >> but assuming you had a more interesting use case: when you expand the >> macro as written, the result is: >> "$string$value", with string=:outstring and value=:(x.value), exactly >> as you specified: "outstringx.value" >> >> but you want the string before interpolation (note that I'm switching >> to the functional form of string interpolation because it is easier to >> read in macro form), so we need this complicated thing to make a macro >> that is actually just a function: >> macro INN(str, val) >> :( v = $(esc(val)); s = $(esc(str)); v != nothing ? string(v, s) : s ) >> end >> >> but the better way to write that is: >> INN( outstring, value ) = value !== nothing ? "$outstring$value" : >> outstring >> macro INN(str, val) >> :( INN($(esc(str)), $(esc(val))) ) >> end >> >> why is this better? it's easier to read, write, and debug (also, >> because it makes it obvious that you should not be using a macro for >> this) >> >> finally, there's the even cleaner options: >> outstring = "$(x.value!==nothing?x.value:"")" >> >> or, using multiple dispatch -- my favorite option (excellent API for >> future extensibility): >> mystr(::Nothing) = "" >> mystr(x) = x >> outstring = "$(mystr(x))" >> >> note that since in your type, you have value::Int, so value will >> always be an Int, never another type (like nothing), so it's a >> pointless test >> >> final note, string concatenation using $ or * or string (all of which >> are exactly equivalent) is going to be slow compared to making an >> IOBuffer, printing / writing / or showing all of your text to the >> buffer, then calling takebuf_string(iobuf) at then end >> >> On Thu, Apr 17, 2014 at 11:38 PM, Ben Ward wrote: >> > Hi Is it possible to use macros inside o functions in Julia if they are >> > expanded at compile time as the manual says? I've been playing with a >> toy >> > type: >> > >> > type MeltingTemperature >> > value::Int >> > end >> > >> > >> > >> > >> > myvar = MeltingTemperature(56) >> > >> > >> > and say I want to make a function that write it out as an XML string: >> > "56 >> > >> > Now I want to make a function that constructs that string by 1). Adding >> the >> > open tag 2). Checking the temperature is not nothing and if it is not, >> > including it in the string. 3). add the closing tag. >> > >> > I figured step 2 would be a good candidate for a macro for a larger >> type as >> > checking each value is not nothing would be tedious. So: >> > >> > macro INN(string, value) >> > value != nothing ? "$string$value" : "$string" >> > end >> > >> > >> > function writePhyXML(x::MeltingTemperature) >> > outstring = "" >> > outstring = @INN outstring x.value; >> > outstring = "$(outstring)" >> > outstring >> > end >> > >> > >> > I figured the macro would be expanded and the function definition would >> > become: >> > >> > function writePhyXML(x::MeltingTemperature) >> > outstring = "" >> > outstring = x.value != nothing ? "$outstring$x.value" : "$outstring" >> > outstring = "$(outstring)" >> > outstring >> > end >> > >> > >> > But results in "outstringx.value" >> > >> > Is it possibl