How to initialise an abstract in Julia? - julia

Julia> abstract Shape
ERROR: syntax: extra token "Shape" after end of expression
Stacktrace:
[1] top-level scope at REPL[64]:0
Just wanted to create an abstract but it says following even when I use help?>
Is there any alternate to this?
help?> abstract
search: AbstractSet abstract type AbstractChar AbstractDict AbstractFloat
Couldn't find abstract
Perhaps you meant struct or AbstractSet
No documentation found.
Binding abstract does not exist.

The correct syntax is abstract type Shape end.
You can find the docs in the REPL help mode with the full keyword:
help?> abstract type
There is online documentation on the keyword and more general documentation on types.

Related

Models.Fitting type failure

I've inherited some old code, which was written for a much earlier version of Julia (~v0.6). I'm running Julia 1.5.4 and I've already adjusted a lot of the existing code, without much trouble.
But when I run:
import Models
type GLMA <: Models.Fitting.AbstractFittingAlgorithm
end
I get
ERROR: syntax: extra token "GLMA" after end of expression
Stacktrace:
[1] top-level scope at none:1
Why is this happening?
(a) Is there an issue with the type part?
Additionally, (b) Why is Models.Fitting missing when I do this:
Models.Fitting
ERROR: UndefVarError: Fitting not defined
Stacktrace:
[1] getproperty(::Module, ::Symbol) at .\Base.jl:26
[2] top-level scope at REPL[4]:1
I think you might have to declare it as an abstract type rather than a "bare" type. For example:
import Models
abstract type GLMA <: Models.Fitting.AbstractFittingAlgorithm; end
I don't see any bare type references, just abstract and primitive:
Types
Abstract Types
So with the following I was able to reproduce your error message:
julia> abstract type X end
julia> type Y <: X end
ERROR: syntax: extra token "Y" after end of expression
Stacktrace:
[1] top-level scope at none:1
A remote possibility is that the old code brought Fitting into scope with import or using and the keyword 'as' and if that renaming is not currently done, then you've lost that link. More here:
https://docs.julialang.org/en/v1/manual/modules/#Renaming-with-as

Anonymous arguments in julia

Julia permits function and method definitions with unnamed arguments.
This is not mentioned in the functions documentation, nor is it explicitly discussed in the methods documentation. For example:
function myfunc(::Int)
println("Hello!")
end
How should I describe this behavior (I've googled "anonymous arguments" without success), and when is it useful?
This behavior is useful for method dispatch, when you care only about argument type not argument value. Most often this is a case when what you dispatch on is a singleton type.
An example is:
julia> Vector{String}(undef, 3)
3-element Array{String,1}:
#undef
#undef
#undef
This function is defined in the following way:
Array{T,1}(::UndefInitializer, m::Int) where {T} =
ccall(:jl_alloc_array_1d, Array{T,1}, (Any, Int), Array{T,1}, m)
And you can see that we only care that the first argument was of UndefInitializer type, which is in turn defined as:
struct UndefInitializer end
const undef = UndefInitializer()
We see that UndefInitializer is a singleton type, so we do not care about the value of a variable of this type, but only about its type.
Another common singleton type in Base is Missing. Here are example definitions from Base of standard functions getting a Missing as an argument:
for f in (:(acos), :(acosh), :(asin), :(asinh), :(atan), :(atanh),
:(sin), :(sinh), :(cos), :(cosh), :(tan), :(tanh),
:(exp), :(exp2), :(expm1), :(log), :(log10), :(log1p),
:(log2), :(exponent), :(sqrt))
#eval $(f)(::Missing) = missing
end
(again - you can see that we do not care about the value of the variable - we know its type is Missing so we return missing)
In the Julia manual you have examples of such methods e.g. here but admittedly as far as I can tell the manual does not give a name for this style of method definition.

Can you have types that refer to each other in Julia?

I get ERROR: LoadError: UndefVarError: Expression not defined for the following code:
struct IntLiteral
value::Int
end
struct Plus
left::Expression
right::Expression
end
struct Minus
left::Expression
right::Expression
end
const Expression = Union{IntLiteral, Plus, Minus}
If I declare Expression ahead of Plus and Minus, I get a similar error. Wrapping the code in a module doesn't change anything, either.
Is there a way to reference a type ahead of its declaration in Julia? If not, what is the recommended solution for cases like this, where two types depend on each other? Just remove the type annotations?
In this particular case, I believe I could make Expression an abstract type, and have the others be subtypes of it. Is that recommended in this case? What about the general case?
Not currently, no. See issue #269 for more details.

Parametric functors in Julia

Starting 0.6 it is possible to create parametric methods in Julia using where syntax. According to the release notes of 0.6 version, where syntax
can be used anywhere a type is accepted
Now consider the following contrived example:
function (rng::R)() where {R <: Range}
return first(rng)
end
which, when I attempt to compile it, gives the following error:
ERROR: function type in method definition is not a type
So my question is what is the proper way to create parametric functors in Julia 0.6+?
Ohkay, I get what you are trying to do basically. To understand functors here is a short example code.
julia> struct Student
name::String
end
julia> function (::Student)()
println("Callable of Student Type!")
end
julia> object = Student("JuliaLang")
Student("JuliaLang")
julia> object()
Callable of Student Type!
but when I try to create the parametric functors, it throws out the error similar to yours!
julia> function (::T)() where {T <: Student}
println("Callable of Student Type!")
end
ERROR: function type in method definition is not a type
This problem is actually still OPEN as a issue as #gnimuc rightly pointed out.
You mix up two things
parametric methods e.q. julia> same_type(x::T, y::T) where {T} = true
function-like objects e.g. julia> function (p::Polynomial)(x) ... end
To my knowledge there is no "parametric function-like objects"
However, the following code should be the same of what you intend.
Julia> function (rng::Range)()
return first(rng)
end
cannot add methods to an abstract type
The current docu does not mention any limitation of function-like objects to concrete type, but unfortunately Julia doesn't accept it anyway.

How to get generic type definition for CRTP type

Given the following CRTP type in C#:
public abstract class DataProviderBase<TProvider>
where TProvider : DataProviderBase<TProvider> { }
How would I get its generic type definition in F#?
let typeDef = typedefof<DataProviderBase<_>>
yields the error:
Type constraint mismatch when applying the default type 'DataProviderBase<'a>' for a type inference variable. The resulting type would be infinite when unifying ''a' and 'DataProviderBase<'a>' Consider adding further type constraints
In C#, it would be:
var typeDef = typeof(DataProviderBase<>);
UPDATE
I found a workaround:
[<AbstractClass>]
type DummyProvider() =
inherit DataProviderBase<DummyProvider>()
let typeDef = typeof<DummyProvider>.BaseType.GetGenericTypeDefinition()
Is there another way to do it, without the extra type?
I think this is actually a very good question. I didn't find a better workaround for this.
You can slightly simplify your workaround by using typedefof like this:
let typeDef = typedefof<DataProviderBase<DummyProvider>>
TECHNICAL DETAILS
The problem is that F#'s typedefof<'T> is just an ordinary function that takes a type argument (unlike typeof in C#, which is an operator). In order to call it, you need to give it an actual type and the function will then call GetGenericTypeDefinition under the cover.
The reason why typedefof<option<_>> works is that F# specifies a default type as an argument (in this case obj). In general, F# chooses the less concrete type that matches the constraints. In your case:
DataProviderBase<_> will become DataProviderBase<DataProviderBase<_>> and so on.
Unless you define a new type (as in your workaround), there is no concrete type that could be used as a type argument of typedefof<...>. In this case, the defaulting mechanism simply doesn't work...

Resources