# Simple parametric type question

Hi folks,
I guess I have trouble defining a struct of a giving type and creating it, just because of the (failing to know/understand) the syntax. I was used to create structs in the form

``````mutable struct crocodile
teeth :: Int
legs  :: Float64
crocodile() = new()
end
``````

such that I can just create an object of this kind by simply hitting

``````wally_gator() = new()
``````

and fill in only the fields I want to have, leaving the rest undefined

``````wally_gator.legs = 4
``````

Now the thing is that I want to do the same, but using a parametrized type, something of the form

``````mutable struct animal{T}
x :: Int
y :: T
...
end
``````

I wonder what the equivalent to the

``````crocodile() = new()
``````

statement is, including the T type argument. I’ve tried things like

``````animal{T}) where T = new{T}()
``````

but that fails when trying to create an instance of this object with

``````krok = animal{Float64}()
``````

Could you please provide some help?

Thx,

Ferran.

Not sure what the actual question is, but syntactically you’re missing an `end`:

``````mutable struct crocodile end
``````

There are two sorts of `struct` one is spelled `mutable struct` and the other is spelled `struct`. A `struct` has fields that are value associated at the time that a realization/occurance/instance of the `struct` is constructed. A `mutable struct` has fields that are initially associated at that same event-time; the value immediately assigned to a field (the name of the thing associated) of a `mutable struct` can be updated/altered. If you have a `struct` with a field that holds a container of some sort, you can alter the contents of the container – you cannot alter the specific container given that field. `mutable structs` have fields you can mutate/alter.

What is the `T`? What type[s] can the field `y` be?

Often the parameter is used to differentiate e.g. the type of number (Float/Int and/or sizeof(Float/Int)) or to track a count (like the number of entries in a Tuple: (1, 2, 3) has 3 entries and is of type `NTuple{3,Int}`. If you have a field that may take 2-tuples or 3-tuples, for example, then you may use a parameter to capture the specific length of tuple that occurs in each instance:

``````struct KeepLengthInParam{N}
value::NTuple{N, Int}  # the N here is the same N as the N parameter

function KeepLengthInParam(value::NTuple{N, Int}) where {N}
return new{N}(value)
end
end

example1 = KeepLengthInParam( (1, 2, 3) )
typeof(example1)

example2 = KeepLengthInParam( (1, 2) )
typeof(example2)
``````

try it

either Float64 or Int, essentially

``````struct FloatOrInt{T}
value::T

function FloatOrInt(value::T) where {T<:Union{Float64, Float32, Int64, Int32}}
return new{T}(value)
end
end
``````

that should do it

if you want to get at the parameter directly

``````whatisit(x::FloatOrInt{T}) where {T} = T

a = FloatOrInt(5)
b = FloatOrInt(5.0)

whatisit(a)
whatisit(b)
``````

sorry I don’t know how to use your solution or this does not seem to work. When I try

``````u = FloatOrInt{Float64}()
``````

I get errors…

``````MethodError: no method matching FloatOrInt()
Closest candidates are:
FloatOrInt(!Matched::T<:Union{Float32, Float64, Int32, Int64}) where T<:Union{Float32, Float64, Int32, Int64} at In[8]:5

Stacktrace:
[1] top-level scope at In[12]:100:
``````
``````u = FloatOrInt(0)
``````

if you want to avoid writing the zero (that’s a bad idea)

``````struct FloatOrInt{T}
value::T

function FloatOrInt(value::T) where {T<:Union{Float64, Float32, Int64, Int32}}
return new{T}(value)
end
end

FloatOrInt() = FloatOrInt(0)

u = FloatOrInt()
``````

Ok that works because your struct has only one field. The fact is that i do want to initialize as FloatOrInt() with NO arguments, just because I this is a reduction from a quite big type with many fields. I hate to have to give default values to everything, mostly considering that in some simulations I use some fields and leave the rest undefined, while in other I use other fields etc. Declaring like

``````u = crocodile()
``````

and then only filling the fields I need

``````u.teeth = 128
``````

is what I want/need. Can this be done? Please notice that replies of the form ‘this is the wrong way to do things, you have to build different types…’ is not useful as by doing that I’d have to change tons of lines of code…

Thanks again,

Ferran.

Please see the code just above your question – it shows you what to do.

``````MyStruct() = MyStruct( <put the default values here once> )
# now , any time you do
x = MyStruct()
# the default values attach
``````

…but there are no default values, that’s what I wanted to say. Is it mandatory to have them? On the original type I posted you see there are no default values.

I do not understand what you mean. It is possible to declare fields to have either an Int or a Float or be `missing`. Is that what you want? What do you do with a struct of fields that have nothing assigned?

A `struct` has fields that are value associated at the time each instance of the `struct` is constructed.

Yes I need to have fields with nothing assigned… As I said, this is because I use large types where only some fields are filled in one simulation, while other fields are filled in other simulations. Please read the original post, the crocodile() type I posted has two fields, I declare wally_gator as a new object of this type, assign one field and do nothing with the other, it remains unassigned.
I want to reproduce this behaviour with the parametrized type, if possible…

You can try this:

``````julia> mutable struct animal{T}
x :: Int
y :: T
animal{T}() where {T} = new()
end

julia> krok = animal{Float64}()
animal{Float64}(112604960, 8.10255564e-316)

julia> krok.x=2
2

julia> krok.y=50.0
50.0

julia> krok
animal{Float64}(2, 50.0)
``````
2 Likes

I did read your original post. Perhaps you might revisit mine. What you want is way to denote that some fields are `absent`, `devoid of a set value` and in other runs those fields may get assigned a specific value and others may be “unused” — even when a field is “unused” it exists and as it exists, you do not want it storing garbage; you want to be able to assign the value that means “this is an unused field” which is a value. There is a way to do this, although it is unclear that that would work best for you.

When a field holds the value “this field is not being used now”, what happens in the evaluation routine … is that field ever accessed to see if it is being used or not? Or do you have multiple routines, each of which accesses only a specific subset of the fields available? The approach that is most appropriate depends on these sorts of considerations. There is no immediate match to the syntax that you provided originally, that is not Julia code. There are approaches which likely get done what you need done. I understand that you feel you have entirely specific … please realize there may be considerations and qualifications that you had not yet made clear.

Oh… sorry I I sounded a bit too rough but that was not my intention. I’m not an English native speaker and sometimes the fine details of the proper narrative escape me. In fact I can only thank you for your help and efforts, any other side effect was totally unwanted.

I will try your last form once I’m back at the office. I tried many different combinations similar to this with different {} and () combinations, but maybe not this one (which will probably be the right one). I’ll report back once I try…

Your considerations about different possibilities and interpretations may be right. I certainly had the impression I was completely specifying the problem, but maybe I was not as you say…

Thanks again,

Ferran

1 Like
``````julia> mutable struct animal{T}
x :: Int
y :: T
animal{T}() where{T} = new{T}()
end

julia> a = animal{Float64}()
animal{Float64}(4715867728, 5.0e-324)

julia> a.x = 2
2
``````

I have seen this approach in many different guises.
As a matter of design practice and out of compassion for my clients, the only situation in which I establish an unknown, nonrepeatable initial assigned state is where I supply all the overwriting immediately thereafter (as with preallocating a vector in Julia).

Where all the struct fields were to be valued following construction, perhaps having been queued, this makes sense to me.

1 Like

But yeah, leaving `isbitstype` fields uninitialized can easily lead to bugs.