Coffeescript assoc array syntax in a list comprehension - associative-array

Hi everyone: I'm often running into the following issue with coffeescript and was wondering if anyone knows of a solution. Consider the following code:
k=for x in [0...3]
{foo:{bar:x,baz:3},qux:5}
I have a lot of code that has this basic layout. However, it is hard to read. It would be cleaner to write this code in the following manner:
#Gives Error- PARSE ERROR ON LINE 5: UNEXPECTED 'TERMINATOR'
k=for x in [0...3]
foo:
bar:x
baz:3
qux:5
This error can be circumvented with the following hack, which looks really ugly:
k=for x in [0...3]
g=
foo:
bar:x
baz:3
qux:5
g
Does anybody know a clean way to use Coffeescript's multi-line assoc array syntax inside of a comprehension without running into this error? Thanks for your help!

So,
k=for x in [0...3]
foo:
bar:x
baz:3
qux:5
fails to compile, but
func
foo:
bar:x
baz:3
qux:5
(for instance) compiles correctly. I believe this is a known bug in the CoffeeScript parser. Unfortunately, there are several similar issues open, as parsing YAML-style objects has turned out to be exceptionally tricky. So for now, I'd use explicit curly braces, as c3rin suggests.
[Edit: See issue 981 specifically.]

.map() is your friend here:
k = [0...3].map (i) ->
foo:
bar: "#{i}"
baz: i
qux: i*3
(i know your problem is actually a bug, but this makes more sense IMO. list comprehensions are better suited to simple tasks)

I've changed my answer a couple of times, but I think the issue with your first example is that coffeescript compiler thinks that foo: is the object you want to build and is concerned when it gets to qux: because it thinks its a different object altogether than foo. What's interesting is that you can mix the JSON-style and YAML-style declarations, using the JSON-style curly braces to explicitly declare the boundaries of the object definition, and the use YAML inside of the boundaries for readability.
{
foo:
bar:x
baz:3
qux:5
}

My usual solution for this is the following:
k = for x in [0...3]
g =
foo:
bar:x
baz:3
qux:5
Setting a variable returns the value it is set to. Its still a bit hacky, but slightly nicer than your version that explicitly returns g after setting it. Definitely a workaround for a coffeescript bug, though.

Related

How do I reload a module under development in Julia 1.6?

I know this question has been asked and answered before, but none of the many answers work for me as described.
What is the procedure for reloading a module that I'm working on in Julia (1.6)?
For example, I have
module MyModule
export letters
const letters = String('A':'Z')
end
and I want the be able to load the module, make changes to letters in the module's file, and then reload the module and have those changes reflected in subsequent uses of letters. This seems simple enough, but I can't get it to work.
I've tried
include("src/MyModule.jl")
using .MyModule
but if I change the definition of letters in MyModule.jl and then
include("src/MyModule.jl")
letters doesn't change, unless I fully qualify its use each time with Main.MyModule.letters: using Main.MyModule; letters refers, for example, to the old definition.
How do I reload a module under development so that I can refer to its definitions without fully qualifying them (and without having an unqualified shadow definition always lying around)?
I would just use Revise.jl and wrap everything in functions:
module MyModule
export letters
letters(char_start, char_end) = char_start:char_end |> String
end
julia> using Revise
julia> includet("src/MyModule.jl")
julia> using .MyModule
julia> letters('l', 'p')
"lmnop"
module MyModule
export letters
letters(char_start, char_end) = char_start:char_start |> String
end
julia> letters('l', 'p')
"l"
const is for defining things that you do not want to modify, so I would not expect your original version to work as expected. Revise.jl should also throw a redefinition error if you try to change it
In general though, it's usually much nicer (and easier too!) to just put everything in a package and use the usual using/import syntax. PkgTemplates.jl is great for this
If you would like to redefine consts though, I would definitely recommend checking out Pluto.jl

ERROR: setfield! immutable struct cannot be changed in Julia

I am updating some old code and I am now getting errors: ERROR: setfield! immutable struct cannot be changed in Julia when I try to change the values of an immutable struct. Is there a common workaround for how I can edit/mutate those values (this may be a rather silly question given that the type is explicitly immutable so it's not a good idea generally to try and change it).
As far as I remember immutables can not be safely manipulated even if you get a memory pointer to them and try to use ccal.
However, as an imperfect workaround you can consider using Setfield package as in the example below.
using Setfield
struct S
a::Int
b::String
end
Using:
julia> s = S(2, "hello")
S(2, "hello")
julia> s = #set s.a = 5
S(5, "hello")
Note that in many scenarios this might be faster than actually changing type of S to mutable.

Julia - Array of UTF8 behavior

I encountered a problem which I've solved, but why the solution works doesnt make sense to me
I had a function similar to this one
function testB(a::Array{AbstractString})
println(a)
end
running it like so gave me
testB(convert(Array{UTF8String},["a","b"]))
ERROR: MethodError: `testB` has no method matching
testB(::Array{UTF8String,1})
Note that Im not manually converting to UTF8 in reality, its for demonstration, in reality I have an AbstractString array, but when I fetch elements from it, they become UFT8
My solution reads in short
function testA{T <: AbstractString}(a::Array{T})
println(a)
end
running this method gives
testA(convert(Array{UTF8String},["a","b"]))
UTF8String["a","b"]
Can anyone tell me why testA works but testB doesnt?
Also, is there a name for this {T <: SomeDataType} notation?
While UTF8String is a subtype of AbstractString, Array{UTF8String} is not a subtype of Array{AbstractString} (no covariance). Hence your testB does not work. (But testB(convert(Array{AbstractString},["a","b"])) should work.)
Rationale for why it has to be like this: a function f(x::Vector{AbstractString}) could e.g. push! a new FooString into x (assuming FooString is a subtype of AbstractString). Now if x was in fact a Vector{UTF8String}, that would fail.

How do you find where a macro is from in Julia?

How do you find out where a macro is from in Julia. I'm looking at someone's code and they're using an #debug("string") macro. There are no using statements in the particular file that would tell me where it's loaded from, so I assume it's loaded form somewhere else in the code.
I might guess at the debug module for Julia, but it doesn't seem like it's being used that way, it seems like it's being used more for logging, so I'm a bit unsure of how to track it down through the code.
A macro location can be obtained using the #which macro, this is a feature introduced in 0.5.
julia> #which #printf("%0.2f", 1/3)
#printf(args...) at printf.jl:1178
Similar to #which, you can use #edit to open the source file and #functionloc to get the function location programmatically.
You can go to help mode in the Julia repl by keyboard shortcut shfit+?
help?> #debug
No documentation found.
#debug is a macro.
# 1 method for macro "#debug":
#debug(msg...) at /home/guo/.julia/v0.5/Logging/src/logging_macros.jl:11
I guess the marco #debug is probably from the package Logging.jl.

In Julia, can a macro access the inferred type of its arguments?

In Julia, is there a way to write a macro that branches based on the (compile-time) type of its arguments, at least for arguments whose types can be inferred at compile time? Like, in the example below, I made up a function named code_type that returns the compile-time type of x. Is there any function like that, or any way to produce this kind of behavior? (Or do macros get expanded before types are inferred, such that this kind of thing is impossible.)
macro report_int(x)
code_type(x) == Int64 ? "it's an int" : "not an int"
end
Macros cannot do this, but generated functions can.
Check out the docs here: https://docs.julialang.org/en/v1/manual/metaprogramming/#Generated-functions-1
In addition to spencerlyon2's answer, another option is to just generate explicit branches:
macro report_int(x)
:(isa(x,Int64) ? "it's an int" : "not an int")
end
If #report_int(x) is used inside a function, and the type of x can be inferred, then the JIT will be able to optimise away the dead branch (this approach is used by the #evalpoly macro in the standard library).

Resources