# Floats or Integers or Vectors with specific ranges?

#1

Very basic questions:

• can I define an Int8 Type that can only range from 5 to 20, but throws an error if I try to assign 21 ?
• can I define a Float64 Type that can only range from 1.0 to Infinity, if I try to assign 0.5 ?
• can I define a Vector (e.g., of Floats) that must be of length 5 (or null), but throws an error if I try to assign a vector of length 4 or 6??

I suspect no, except with my own code (e.g., checking when assigning, structs with custom initializers that are checking, etc). Types are already complicated enough. I am just asking for confirmation.

#2

Huh? How else would you define something, but with your own code?

``````julia> struct FiveToTwenty <: Unsigned
val::UInt8
function FiveToTwenty(val)
@assert val >= 5 && val <= 20
new(UInt8(val))
end
end

julia> Base.show(io::IO, v::FiveToTwenty) = print(io, v.val)

julia> FiveToTwenty(4)
ERROR: AssertionError: val >= 5 && val <= 20
Stacktrace:
[1] FiveToTwenty(::Int64) at ./REPL[159]:4

julia> FiveToTwenty(14)
14

julia> FiveToTwenty(24)
ERROR: AssertionError: val >= 5 && val <= 20
Stacktrace:
[1] FiveToTwenty(::Int64) at ./REPL[159]:4

julia> isbits(FiveToTwenty(14))
true
``````

Ideas for others would be similar. For the vector, you may just want to use a mutable struct with 5 fields, or wrap an MVector (from `StaticArrays.jl`).

#3

The better question is, what are you trying to do? If youâre trying to constrain optimization variables, thereâs better ways to do that. If youâre trying to enforce constraints in a nonlinear equation, a transformation could help. Etc.

#4

thanks. Chris, I am just trying to impose discipline on my code, and perhaps get lucky finding errors along the way (rather than with `assert`s). I am also just trying to learn the feature set of julia. I believe the optimization routines have box constraints, which I will work with later.

Elrod, are you running 0.6.2?

``````julia> struct FiveToTwenty <: Unsigned
val::UInt8
function FiveToTwenty(val)
@assert val >= 5 && val <= 20
new(UInt8(val))
end
end

julia> FiveToTwenty(14)
Error showing value of type FiveToTwenty:
ERROR: MethodError: no method matching leading_zeros(::FiveToTwenty)
Closest candidates are:
leading_zeros(::Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8}) at int.jl:238
Stacktrace:
[1] hex(::FiveToTwenty, ::Int64, ::Bool) at ./intfuncs.jl:543
[2] display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::MIME{Symbol("text/plain")}, ::FiveToTwenty) at ./REPL.jl:122
[3] display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::FiveToTwenty) at ./REPL.jl:125
[4] display(::FiveToTwenty) at ./multimedia.jl:218
[5] eval(::Module, ::Any) at ./boot.jl:235
[6] print_response(::Base.Terminals.TTYTerminal, ::Any, ::Void, ::Bool, ::Bool, ::Void) at ./REPL.jl:144
[7] print_response(::Base.REPL.LineEditREPL, ::Any, ::Void, ::Bool, ::Bool) at ./REPL.jl:129
[8] (::Base.REPL.#do_respond#16{Bool,Base.REPL.##26#36{Base.REPL.LineEditREPL,Base.REPL.REPLHistoryProvider},Base.REPL.LineEditREPL,Base.LineEdit.Prompt})(::Base.LineEdit.MIState, ::Base.AbstractIOBuffer{Array{UInt8,1}}, ::Bool) at ./REPL.jl:646
``````

Your example (after I get it to work) was unintuitive to me. I thought of a struct as a composite type, while an Int is a base type; and I think you are defining a struct to be a subtype of a base type. Gotta learn and experiment moreâŚ

/iaw

#5

You need to define Base.show for this type.

``````julia> struct FiveToTwenty <: Unsigned
val::UInt8
function FiveToTwenty(val)
@boundscheck val >= 5 && val <= 20
new(UInt8(val))
end
end

julia> FiveToTwenty(14)
Error showing value of type FiveToTwenty:
ERROR: MethodError: no method matching leading_zeros(::FiveToTwenty)
Closest candidates are:
leading_zeros(::Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8}) at int.jl:238
Stacktrace:
[1] hex(::FiveToTwenty, ::Int64, ::Bool) at ./intfuncs.jl:543
[2] display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::MIME{Symbol("text/plain")}, ::FiveToTwenty) at ./REPL.jl:122
[3] display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::FiveToTwenty) at ./REPL.jl:125
[4] display(::FiveToTwenty) at ./multimedia.jl:218
[5] eval(::Module, ::Any) at ./boot.jl:235
[6] print_response(::Base.Terminals.TTYTerminal, ::Any, ::Void, ::Bool, ::Bool, ::Void) at ./REPL.jl:144
[7] print_response(::Base.REPL.LineEditREPL, ::Any, ::Void, ::Bool, ::Bool) at ./REPL.jl:129
[8] (::Base.REPL.#do_respond#16{Bool,Base.REPL.##26#36{Base.REPL.LineEditREPL,Base.REPL.REPLHistoryProvider},Base.REPL.LineEditREPL,Base.LineEdit.Prompt})(::Base.LineEdit.MIState, ::Base.AbstractIOBuffer{Array{UInt8,1}}, ::Bool) at ./REPL.jl:646

julia> x = ans;

julia> Base.show(io::IO, v::FiveToTwenty) = print(io, v.val)

julia> x
14
``````

The hint was that the error said âError showingâŚâ
You created the object just fine, but the error came in displaying the actual value. This is why we could still assign the value (without error), as long as we followed the operation with a semicolon.
Then, defining a show method let you display it.

In Julia, if you want a custom type with certain properties, you can just define it on your own.
If you donât like always having the error checking, you can

``````julia> struct FiveToTwenty2 <: Unsigned
val::UInt8
@inline function FiveToTwenty2(val)
@boundscheck begin @assert val >= 5 && val <= 20 end
new(UInt8(val))
end
end
julia> Base.show(io::IO, v::FiveToTwenty2) = print(io, v.val)

julia> f(x) = (@inbounds x = FiveToTwenty2(x); x)
f (generic function with 1 method)

julia> FiveToTwenty2(21)
ERROR: AssertionError: val >= 5 && val <= 20
Stacktrace:
[1] FiveToTwenty2(::Int64) at ./REPL[52]:4

julia> f(11)
11

julia> f(21)
21
``````

Thus, once youâve confirmed your code never violates the bounds, you can add the `@inbounds` and turn bounds checking off.

Although if someone else put a lot of time into a solution, of course itâs easier to take advantage of their work. Peopleâve asked a few times what the best way to actually discover packages is thoughâŚ

Anyway, if youâre facing constrained optimization problems with straightforward constraints (eg, 1 < y < infinity), a straightforward approach is as in:

Where you transform the variables from the constrained to an unconstrained version.
Eg, -infinity < log(y-1) < infinity. The above package handles transforms like this, as well as providing everything else, like Jacobians and the inverse transforms.

For the third case,

``````julia> using StaticArrays

julia> FiveVector1{T} = MVector{5,T}
StaticArrays.MArray{Tuple{5},T,1,5} where T

julia> FiveVector2{T} = SizedArray{Tuple{5},T}
StaticArrays.SizedArray{Tuple{5},T,N,M} where M where N where T

julia> FiveVector1(randn(5))
5-element MVector{5,Float64}:
0.804218
3.43472
-0.786301
0.47925
1.69257

julia> FiveVector2(randn(5))
5-element StaticArrays.SizedArray{Tuple{5},Float64,1,1}:
-1.37541
0.969937
0.364058
-0.364662
-2.35112
``````

#6

thanks, again, Elrod. GrrrâŚI should have made this multiple questions. I had expected a âno workâ and move on. julia feels more like perl, in that there are so many things to discover, than like C, where it is easy to learn and then remember everything.

thank you for explaining where I messed up on the `FiveToTwenty`. instead of defining `show`, is it possible to tell julia that the FiveToTwenty type can be promoted to an Integer? Then, not only would the print work automatically , but also examples like

``````julia> 15+FiveToTwenty(14)
ERROR: no promotion exists for Int64 and FiveToTwenty
``````

I did not see a working example in the docs, so I tried

``````julia> promote_rule(::Type{Int}, ::Type{FiveToTwenty}) = Int
ERROR: error in method definition: function Base.promote_rule must be explicitly imported to be extended
``````

As a sidenote, Pascal had a few type innovations decades ago, one of which were range types. juliaâs innovations in the type realm are fascinating, and not just a little syntactic sugar, but a lot. One needs a lot of insulin to digest it.

#7

If you want to extend a function from another module, you have to preface the name with the module (see the error message).
For example, instead of `show`, I had to say `Base.show`.

In your case, that means (you also need to define convert methods, so Julia knows how to do the conversion):

``````Base.promote_rule(::Type{Int}, ::Type{FiveToTwenty}) = Int
Base.convert(::Type{Int}, x::FiveToTwenty) = Int(x.val)
FiveToTwenty(14) + 2
FiveToTwenty(14) + 20
``````

The output is of a regular integer (64 bit on 64 bit systems).
That doesnât for for showing though.
Honestly, I havenât messed with displays for custom types nearly enough, so Iâm not really sure what the best way to do things are. If you delete the `<: Unsigned` part, it will display automatically as:

``````julia> struct FiveToTwenty3
val::UInt8
@inline function FiveToTwenty3(val)
@boundscheck begin @assert val >= 5 && val <= 20 end
new(UInt8(val))
end
end

julia> FiveToTwenty3(8)
FiveToTwenty3(0x08)

julia> isbits(ans)
true
``````

A fallback show for numeric types doesnât seem to be defined. The above is normal, although not especially pretty.

If youâre adding a lot of new types, you can

``````import Base: promote_rule
promote_rule(::Type{Int}, x::FiveToTwenty) = Int(x.val)
``````

In Julia, you can get range types like

``````julia> typeof(1:20)
UnitRange{Int64}

julia> typeof(linspace(0.3, 17, 100))
StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
``````

I love Juliaâs innovations.
Multiple dispatch is incredible.
I think it can take a while to get used to, but how it lets you get low/zero overhead performant abstractions with extreme generalizationâŚjust mind blowing!

Like, about a month ago I was working on a problem, and my answers were nonsense.
The functions involved inverting and multiplying a few (ill-conditioned) matrices. Simply calling BigFloat.() on the inputs -> everything worked, the answers were right, and I had derivative-enhanced quadrature rules.

More impressive of course is how automatic differentiation âjust worksâ on most code, or how @ChrisRackauckas got a bunch of functions to also work on GPUArraysâŚ