I wanted to test how abstract type works in "strcutres", so I created a struct below with a constructor, however, the return message displays "ERROR: MethodError: no method matching Rect(::Int64)".
I don't know which part went wrong, although the parameter "5" that I used fits the definition of the constuctor which is a single integer input. Thank you.
abstract type Shape{T<:Integer,F<:AbstractFloat} end
export Shape
struct Rect{T,F} <: Shape{T,F}
a::T
b::T
c::T
v::F
function Rect{T,F}(a::T) where {T<:Integer, F<:AbstractFloat}
b = 10;
c = 10;
v = a*b*c;
return new(a,b,c,v)
end
end
function main()
vol = Rect(5).v;
println(vol)
end
main()
It should return a product of a, b and c with only a being the input variable.
You do not have the appropriate constructor.
You should do:
julia> Rect{Int,Float64}(5)
Rect{Int64, Float64}(5, 10, 10, 500.0)
Other option is to add the constructor to your struct:
function Rect{T}(a::T) where {T<:Integer}
Rect{Int,Float64}(a)
end
Once you add the constructor you can do:
julia> Rect{Int}(5)
Rect{Int64, Float64}(5, 10, 10, 500.0)
Or you can also define:
Rect(a::Int) = Rect{Int,Float64}(a)
and have
julia> Rect(5)
Rect{Int64, Float64}(5, 10, 10, 500.0)
Related
The code at the end of this post constructs a function which is bound to the variables of a given dictionary. Furthermore, the function is not bound to the actual name of the dictionary (as I use the Ref() statement).
An example:
julia> D = Dict(:x => 4, :y => 5)
julia> f= #mymacro4(x+2y, D)
julia> f()
14
julia> DD = D
julia> D = nothing
julia> f()
14
julia> DD[:x] = 12
julia> f()
22
Now I want to be able to construct exactly the same function when I only have access to the expression expr = :(x+2y).
How do I do this? I tried several things, but was not able to find a solution.
julia> f = #mymacro4(:(x+2y), D)
julia> f() ### the function evaluation should also yield 14. But it yields:
:(DR.x[:x] + 2 * DR.x[:y])
(I actually want to use it within another macro in which the dictionary is automatically created. I want to store this dictionary and the function within a struct, such that I'm able to call this function at a later point in time and manipulate the objects in the dictionary. If necessary, I may post the complete example and explain the complete problem.)
_freevars2(literal) = literal
function _freevars2(s::Symbol)
try
if typeof(eval(s)) <: Function
return s
else
return Meta.parse("DR.x[:$s]")
end
catch
return Meta.parse("DR.x[:$s]")
end
end
function _freevars2(expr::Expr)
for (it, s) in enumerate(expr.args)
expr.args[it] = _freevars2(s)
end
return expr
end
macro mymacro4(expr, D)
expr2 = _freevars2(expr)
quote
let DR = Ref($(esc(D)))
function mysym()
$expr2
end
end
end
end
Let's say, I want to pass a function to another function:
function foo()
return 0;
end
function bar(func)
return func();
end
print(bar(foo));
But you can make functions typesafe:
function func(t::Int)
print(t);
end
func(0); #produces no error
func("Hello world"); #produces an error
I didn't found out, how I combine both, that means, how can I explicitly define a parameter of bar, like func, to be a function, possibly with certain input / output argument types.
Thanks in advance for any help.
If I understand you correctly you want to make sure the passed function returns a specific type? The simplest thing is to just typeassert the return value at runtime:
julia> function f(func)
val = func()::Int # Error if the return value is not of type Int
return val
end
f (generic function with 1 method)
julia> f(() -> 1)
1
julia> f(() -> 1.0)
ERROR: TypeError: in typeassert, expected Int64, got Float64
Stacktrace:
[1] f(::var"#7#8") at ./REPL[5]:2
[2] top-level scope at REPL[8]:1
Alternatively you can use the FunctionWrappers.jl package (which will convert to the specified return type, or error if the conversion is not possible):
julia> using FunctionWrappers: FunctionWrapper
julia> function f(func::FunctionWrapper{Int,<:Tuple})
val = func()
return val
end;
julia> function f(func)
fw = FunctionWrapper{Int,Tuple{}}(func)
return f(fw)
end;
julia> f(() -> 1)
1
julia> f(() -> 1.0) # Can convert to Int
1
julia> f(() -> 1.2) # Can not convert to Int
ERROR: InexactError: Int64(1.2)
A function is of type Function. You can easily check this:
julia> foo() = 1;
julia> T = typeof(foo)
typeof(foo)
julia> supertype(T)
Function
julia> foo isa Function
true
This will not necessarily cover all callable types, as you can make any type callable:
julia> struct Callable end
julia> (::Callable)(x::Number) = x + one(x)
julia> callable = Callable()
Callable()
julia> callable(5)
6
julia> callable isa Function
false
In the following piece of Julia code, st.a and b are the same array, so when I delete an element from st.a, then this element is also deleted from b. Is it possible that a new array "*.a" is generated, every time a create an object * of Mystruct?
struct Mystruct
a::Array{Int64,1}
Mystruct(a::Array{Int64,1}) = new(a)
end
b = [1, 2, 3, 4]
st = Mystruct(b)
deleteat!(st.a,1)
I think that:
struct Mystruct
a::Array{Int64,1}
Mystruct(a::Array{Int64,1}) = new(copy(a))
end
will do the job you want.
I can unpack a tuple. I'm trying to write a function (or macro) that would unpack a subset of these from an instance of the type-constructor Parameters(). That is, I know how to do:
a,b,c = unpack(p::Parameters)
But I would like to do something like this:
b,c = unpack(p::Parameters, b,c)
or maybe even lazier:
unpack(p::Parameters, b, c)
This is to avoid writing things like:
function unpack_all_oldstyle(p::Parameters)
a=p.a; b=p.b; c=p.c; ... z=p.z;
return a,b,c,...,z
end
There's something wrong with my approach, but hopefully there is a fix.
In case it wasn't clear from the wording of my question, I'm a total ignoramus. I read about unpacking the ellipsis here: how-to-pass-tuple-as-function-arguments
"module UP tests Unpacking Parameters"
module UP
struct Parameters
a::Int64
b::Int64
c::Int64
end
"this method sets default parameters and returns a tuple of default values"
function Parameters(;
a::Int64 = 3,
b::Int64 = 11,
c::Int64 = 101
)
Parameters(a, b, c)
end
"this function unpacks all parameters"
function unpack_all(p::Parameters)
return p.a, p.b, p.c
end
"this function tests the unpacking function: in the body of the function one can now refer to a rather than p.a : worth the effort if you have dozens of parameters and complicated expressions to compute, e.g. type (-b+sqrt(b^2-4*a*c))/2/a instead of (-p.b+sqrt(p.b^2-4*p.a *p.c))/2/p.a"
function unpack_all_test(p::Parameters)
a, b, c = unpack_all(p)
return a, b, c
end
"""
This function is intended to unpack selected parameters. The first, unnamed argument is the constructor for all parameters. The second argument is a tuple of selected parameters.
"""
function unpack_selected(p::Parameters; x...)
return p.x
end
function unpack_selected_test(p::Parameters; x...)
x = unpack_selected(p, x)
return x
end
export Parameters, unpack_all, unpack_all_test, unpack_selected, unpack_selected_test
end
p = UP.Parameters() # make an instance
UP.unpack_all_test(p)
## (3,11,101) ## Test successful
UP.unpack_selected_test(p, 12)
## 12 ## intended outcome
UP.unpack_selected_test(p, b)
## 11 ## intended outcome
UP.unpack_selected_test(p, c, b, a)
## (101,11,3) ## intended outcome
There already exists one: Parameters.jl.
julia> using Parameters
julia> struct Params
a::Int64
b::Int64
c::Int64
end
julia> #unpack a, c = Params(1,2,3)
Params(1,2,3)
julia> a,c
(1,3)
julia> #with_kw struct Params
a::Int64 = 3
b::Int64 = 11
c::Int64 = 101
end
julia> #unpack c,b,a = Params()
Params
a: Int64 3
b: Int64 11
c: Int64 101
julia> c,b,a
(101,11,3)
BTW, you can fix your unpack_selected by:
unpack_selected(p::Parameters, fields...) = map(x->getfield(p, x), fields).
# note that, the selected field names should be Symbol here
julia> unpack_selected(p, :b)
(11,)
julia> unpack_selected(p, :c, :b, :a)
(101,11,3)
To declare a new composite type, we use the following syntax
type foo
a::Int64
b::Int64
end
and instantiate like such
x = foo(1,3)
Is there some way to have type attributes that always just a function of other attributes? For example, is there some way to do the following (which is invalid syntax)...
type foo
a::Int64
b::Int64
c = a + b
end
My current workaround is just to define a function which calculates c and returns an instance of the type, like so...
type foo
a::Int64
b::Int64
c::Int64
end
function foo_maker(a, b)
return foo(a, b, a+b)
end
Is there a more elegant solution? Possibly one that can be contained within the type definition?
EDIT - 3/7/14
With Cristóvão's suggestion in mind, I've ended up declaring constructors like the following to allow for keyword args and attributes calculated upon instantiation
# Type with optional keyword argument structure
type LargeType
# Declare all the attributes in order up top
q::Int64
w::Int64
e::Int64
r::Int64
t::Int64
y::Int64
a::Number
b::Number
c::Number
# Declare Longer constructor with stuff going on in the body
LargeType(;q=1,w=1,e=1,r=1,t=1,y=1) = begin
# Large Constructor Example
a = round(r^t - log(pi))
b = a % t
c = a*b
# Return new instance with correctly ordered arguments
return new(q,w,e,r,t,y,a,b,c)
end
end
println(LargeType(r=2,t=5))
Try this:
julia> type foo
a::Int64
b::Int64
c::Int64
foo(a::Int64, b::Int64) = new(a, b, a+b)
end
julia> foo(1,2)
foo(1,2,3)
julia> foo(4,5,6)
no method foo(Int64, Int64, Int64)
However, that won't prevent one from manually changing a, b or c and rendering c inconsistent. To prevent that, if it presents no other problems, you can make foo immutable:
julia> immutable foo
...
There isn't any way to do this currently, but there might be in the future:
https://github.com/JuliaLang/julia/issues/1974