Constructors with explicit and implicit types

I am implementing functor types. A simple example is the absolute value functor. (There is a scaling just to make the problem worthwhile.)

abstract type AbFun{F<:Real} end

struct Magnitude{F} <: AbFun{F}
    scale::F
end
Magnitude() = Magnitude(1.)
(self::Magnitude{F})(x::F) where F =  abs(self.scale*x)

Now I have a function which has a fixed paramter L.

struct Huber{L, F} <: AbFun{F}
    scale::F
end
Huber() = Huber{1., typeof(1.)}(1.)

function (self::Huber{L, F})(x::F) where {L, F}
    sx = abs(self.scale*x)
    sx<1/L ? L*sx*sx/2 : sx-.5/L
end

Now I initialize

m1 = Magnitude()
m2 = Magnitude(2.)
h0 = Huber()
h2 = Huber{2., typeof(2.)}(2.)

and they work. But these fail.

Huber{2.}() # Want L = 2., scale = 1. (default)
Huber(2.) # Want L = 1. (default), scale = 2.
Huber{2.}(3.) # Want L = 2., scale = 3.        *NEED THIS TO WORK*

Thanks!

You need to define

Huber{L}(x::F) where {L,F} = Huber{L,F}(x)
Huber{L}() where L= Huber{L}(1.)
Huber(x::F) where F = Huber{1.}(x)
1 Like

Hmm… I almost thought it was that, but I guess I was confused because in previous versions …

unity{T}(x::T) = one(T)

was same as

unity(x::T) where T = one(T)

Here we seem to have both notations in one! as…

unity{T}(x::T) where T = ...

Also which order is preferred?

struct Huber{L, F} <: AbFun{F} ... end
# or
struct Huber{F, L} <: Abfun{F} ... end

I think the where notation was introduced precisely to avoid that confusion.
Note that unity is a function, not a type.
They changed this syntax unit{T}(x::T) = one(T) to unit(x::T) where T = one(T) so that when you see something like something{T}(x::T)... you can be sure that that is a constructor to a type something with parametric type T, not a function with type signature.


Ps: When you define Huber{L,F}(x::F) = ... you are defining a type constructor, not a function!

2 Likes