Subtypes of composite types - julia

I'm trying to make a vectorized version of ismatch.
Base.ismatch
function ismatch(vector::Vector, regex::Regex)
[ismatch(regex, string) for string in vector]
end
This works, but this
Base.ismatch
function ismatch(vector::Vector{String}, regex::Regex)
[ismatch(regex, string) for string in vector]
end
doesn't because Vector{ASCIIString} <: Vector{String} is false.
Is there any way to get around this?

The reason for your results is julias invariant typing system. This means, although ASCIIString <: String is true, Vector{ASCIIString} <: Vector{String} is false.
To get around, use parametric types:
import Base.ismatch
function ismatch{T<:String}(vector::Vector{T}, regex::Regex)
[ismatch(regex,string), for string in vector]
end

Related

Constrain the range of a parametric type to integer values

I've created a parametrized type where the parameter is an integer. Below is a reasonable MWE.
struct InverseTaylor{N}
a::Vector{Float64}
function InverseTaylor{N}() where {N}
a = something_done_with_n(N)
new(a)
end
end
But I'm unhappy to have the where {N} not constraining the N further.
What I could think of during writing this question is to add a verification in the inner constructor, like so:
N isa Int || error("$N should be an integer")
Yet it still feels like there should be a better way.
P.S. I know there are caveats to using types parameterized on integer values, but I feel like if the language allows for the concept, there should also be a way to make it clear what I expect from N in the struct definition.
would
struct InverseTaylor{N}
a::Vector{Float64}
function InverseTaylor{N}() where N <: Integer
a = something_done_with_n(N)
new(a)
end
end
work for what you want to do?

Easy initialisation of empty containers

Consider the following code.
struct MyType
data::Dict{Int, Float64}
end
MyType() = MyType(Dict{Int, Float64}())
Having to repeat the type of data is a bit clumsy, and the problem gets out of hand very quickly if you have more variables and/or your types get more complicated. Can I avoid this?
If the type in question is default-constructible (i.e., it has a no-args constructor), you can use the following trick.
struct Default; end
Base.convert(::Type{T}, ::Default) where T = T()
struct MyType
data::Dict{Int, Float64}
end
MyType() = MyType(Default())
You can do:
Base.#kwdef struct MyType
data::Dict{Int, Float64} = Dict{Int, Float64}()
end
And now you can just write MyType():
julia> MyType()
MyType(Dict{Int64, Float64}())
I personally more like the package Parameters which is additionally affecting how struct is displayed:
using Parameters
#with_kw struct MyType
data::Dict{Int, Float64} = Dict{Int, Float64}()
end
And now in REPL you can see:
julia> MyType()
MyType
data: Dict{Int64, Float64}
The following hack-ish method works (as of Julia 1.8):
MyType() = MyType((t() for t in MyType.types)...)
It doesn't include Int or Float64, so it passes OP conditions. And also, it generalizes to types with many fields, and complex ones because it is essentially recursive.

In Julia: initialize fields with nothing

I have a mutable struct with optional fields like this:
mutable struct MyStruct
field1::Union{Int, Nothing}
field2::Union{String, Nothing}
field3::Union{Int, Nothing}
field4::Union{String, Nothing}
# ...
end
I can now write a default constructor which initializes the fields with nothing:
MyStruct() = MyStruct(nothing, nothing, nothing, nothing)
This is not so nice when my struct has many fields. Also, I have to count the fields to get the constructor call with all the 'nothings' correct in this case. Is there a better way to do that?
Depending on the field content, I want to call different functions later:
if mystruct.field1 == nothing
do_this()
else
do_that()
end
You can use fieldcount function to achieve that. This function gives you the number of fields of that an instance of given type would have. Here is an example containing a mutable struct and an outer constructor.
julia> mutable struct Foo
x
y
z
end
julia> Foo() = Foo(ntuple(x->nothing, fieldcount(Foo))...); # you can also fill an array and use `...`
julia> Foo()
Foo(nothing, nothing, nothing)

constrain argument to be in a set of values in Julia function signature

Is there a way in Julia to specify that a function argument can take one of a set of values through type annotations? For example, let's say I have function foo which accepts a single argument
function foo(x::String)
print(x)
end
the argument x can only be a String. Is there a way to further constrain it in the function signature so that it can only be for example one of the strings "right", "left", or "center"?
In Julia, the motto should be "There's a type for that!".
One way of handling this would be to create a type with a constructor that only allows the values you want (and possibly stores them in a more efficient manner).
Here is one example:
const directions = ["left", "right", "center"]
immutable MyDirection
Direction::Int8
function MyDirection(str::AbstractString)
i = findnext(directions, str, 1)
i == 0 && throw(ArgumentError("Invalid direction string"))
return new(i)
end
end
Base.show(io::IO, x::MyDirection) = print(io, string("MyDirection(\"",directions[x.Direction],"\")"))
function foo(x::MyDirection)
println(x)
end
function foo(str::AbstractString)
x = MyDirection(str)
println(x)
end
test = MyDirection("left")
foo(test)
foo("right")
Note: my example is written with Julia 0.4!
Edit:
Another approach would be to use symbols, such as :left, :right, and :center,
instead of strings.
These have the advantage of being interned (so that they can be compared simply by comparing their address), and they can also be used directly for type parameters.
For example:
immutable MyDirection{Symbol} ; end
function MyDirection(dir::Symbol)
dir in (:left, :right, :center) || error("invalid direction")
MyDirection{dir}()
end
MyDirection(dir::AbstractString) = MyDirection(symbol(dir))
That will let you do things like:
x = MyDirection("left")
which will create an immutable object of type MyDirection{:left}.
No, it is not. That would be dispatching on values, which isn't possible in Julia.
I'm not sure what your actual application is, but there are some possibly-appropriate workarounds to this, e.g.
abstract Sam81Args
type ArgRight <:Sam81Args end
type ArgLeft <:Sam81Args end
type ArgCenter <:Sam81Args end
function foo{T<:Sam81Args}(x::Type{T})
println(T)
end
foo(ArgCenter)

julia interpolation of own type with string()

I'm quite new to Julia and I'm looking into porting some Python code to Julia. This code uses __repr__() overloading to display cutsom types. I understand that Julia provides the string() method for this functionality. But I can't figure it out.
julia> type Thomas
t::Integer
end
julia> function Base.string(t::Thomas)
"---> $(t.t) <---"
end
julia> r = Thomas(8);
With these definitions I expected my string(::Thomas) function to be called whenever a value of type Thomas needed to be converted to a string. In one case, it works as expected:
julia> println("$r")
---> 8 <---
But, for the most cases it does not:
julia> println(r)
Thomas(8)
julia> println(" $r")
Thomas(8)
julia> println("r = $r")
r = Thomas(8)
julia> repr(r)
"Thomas(8)"
What did I get wrong ? Is there some other function I should define for my new custom type ?
I am running Julia 0.4.0-dev. (the code above was pasted from the REPL of Version 0.4.0-dev+3607 (2015-02-26 07:41 UTC), Commit bef6bf3*, x86_64-linux-gnu)
At the moment just overriding Base.show should be enough, as follows.
type Thomas
t::Int # note Int not Integer
end
Base.show(io::IO, x::Thomas) = print(io, "Thomas with $(x.t)")
Note that in the definition of the type, you should use the concrete type Int (equivalent to Int64 or Int32, depending on your machine's word size), not the abstract type Integer, which will lead to bad performance.
The situation with Base.show, Base.print etc. is indeed confusing at the moment, but with some recent work (look up IOContext) should get simplified and clarified soon.
You have to override two versions of Base.print actually to get a consistent behavior of string interpolation:
Base.print(io::IOBuffer, t::Thomas) = Base.print(io, "---> $(t.t) <---")
Base.print(t::Thomas) = Base.print("---> $(t.t) <---")
Then you'll have:
print(t)
string(t)
string(t, t, ...)
"$t"
"t = $t"
"$t $t $t"
and co.
You may want to override the show method as well.
Base.show(io::IO, x::Thomas) = show(io, string(x))

Resources