TL;DR:
what's the accurate definition of inner constructors? In Julia-v0.6+, is it right to say "any constructor that can be called with the signature typename{...}(...)(note the {} part) is an inner constructor"?
As discussed in the comment below, is the outer-only constructor actually an explicit inner constructor?
Is it right to use methods for checking whether a method is an inner/outer constructor?
What's the difference between the default constructors that automatically defined by Julia and the corresponding ones explicitly defined by users?
BTW, I know how to use and when to use an inner constructor. I knew what an inner constructor is until the outer-only constructors come in and muddied the waters. :(
Let's recall some statements from the doc:
1. Outer Constructor Methods
A constructor is just like any other function in Julia in that its overall behavior is defined by the combined behavior of its methods.
2. Inner Constructor Methods
An inner constructor method is much like an outer constructor method, with two differences: 1. It is declared inside the block of a type declaration, rather than outside of it like normal methods. 2. It has access to a special locally existent function called new that creates objects of the block's type.
3. Parametric Constructors
Without any explicitly provided inner constructors, the declaration of the composite type Point{T<:Real} automatically provides an inner constructor, Point{T}, for each possible type T<:Real, that behaves just like non-parametric default inner constructors do. It also provides a single general outer Point constructor that takes pairs of real arguments, which must be of the same type.
I found inner constructor methods can't be directly observed by methods, even methods(Foo{Int}) works, it's actually not "just like any other function", common generic functions cannot be methodsed in this way.
julia> struct Foo{T}
x::T
end
julia> methods(Foo)
# 2 methods for generic function "(::Type)":
(::Type{Foo})(x::T) where T in Main at REPL[1]:2 # outer ctor 「1」
(::Type{T})(arg) where T in Base at sysimg.jl:24 # default convertion method「2」
julia> #which Foo{Int}(1) # or methods(Foo{Int})
(::Type{Foo{T}})(x) where T in Main at REPL[1]:2 # inner ctor 「3」
However, the outer-only constructors adds another wrinkle to the constructor story:
julia> struct SummedArray{T<:Number,S<:Number}
data::Vector{T}
sum::S
function SummedArray(a::Vector{T}) where T
S = widen(T)
new{T,S}(a, sum(S, a))
end
end
julia> methods(SummedArray)
# 2 methods for generic function "(::Type)":
(::Type{SummedArray})(a::Array{T,1}) where T in Main at REPL[1]:5 # outer ctor「4」
(::Type{T})(arg) where T in Base at sysimg.jl:24
Hmmm, an outer constructor IN a type declaration block, and it calls new as well. I guess the purpose here is just to prevent Julia from defining the default inner-outer constructor pair for us, but is the second statement from the documentation still true in this case? It's confusing to new users.
Here, I read another form of inner constructors:
julia> struct Foo{T}
x::T
(::Type{Foo{T}})(x::T) = new{T}(x)
end
julia> methods(Foo)
# 1 method for generic function "(::Type)":
(::Type{T})(arg) where T in Base at sysimg.jl:24
julia> methods(Foo{Int})
# 2 methods for generic function "(::Type)":
(::Type{Foo{T}})(x::T) where T in Main at REPL[2]:3 「5」
(::Type{T})(arg) where T in Base at sysimg.jl:24
It's far from the canonical form Foo{T}(x::T) where {T} = new(x) but it seems the results are quite the same.
So my question is what's the accurate definition of inner constructors? In Julia-v0.6+, is it right to say "any constructor that can be called with the signature typename{...}(...)(note the {} part) is an inner constructor"?
By the way of example, suppose you want to define a type to represent even numbers:
julia> struct Even
e::Int
end
julia> Even(2)
Even(2)
So far so good, but you also want the constructor to reject odd numbers and so far Even(x) does not:
julia> Even(3)
Even(3)
So you attempt to write your own constructor as
julia> Even(x) = iseven(x) ? Even(x) : throw(ArgumentError("x=$x is odd"))
Even
and ... drum roll, please ... It does not work:
julia> Even(3)
Even(3)
Why? Let's ask Julia what she has just called:
julia> #which Even(3)
Even(e::Int64) in Main at REPL[1]:2
This is not the method that you defined (look at the argument name and the type), this is the implicitly provided constructor. Maybe we should redefine that? Well, don't try this at home:
julia> Even(e::Int) = iseven(e) ? Even(e) : throw(ArgumentError("e=$e is odd"))
Even
julia> Even(2)
ERROR: StackOverflowError:
Stacktrace:
[1] Even(::Int64) at ./REPL[11]:0
[2] Even(::Int64) at ./REPL[11]:1 (repeats 65497 times)
We've just created an infinite loop: we redefined Even(e) to recursively call itself. We are now facing a chicken and egg problem: we want to redefine the implicit constructor, but we need some other constructor to call in the defined function. As we've seen calling Even(e) is not a viable option.
The solution is to define an inner constructor:
julia> struct Even
e::Int
Even(e::Int) = iseven(e) ? new(e) : throw(ArgumentError("e=$e is odd"))
end
julia> Even(2)
Even(2)
julia> Even(3)
ERROR: ArgumentError: e=3 is odd
..
Inside an inner constructor, you can call the original implicit constructor using the new() syntax. This syntax is not available to the outer constructors. If you try to use it, you'll get an error:
julia> Even() = new(2)
Even
julia> Even()
ERROR: UndefVarError: new not defined
..
Related
So I have been trying to adapt my python codes to Julia instead of fortran mainly because of the fact I have Jupiter to easily test my work on the fly. But in Julia 1, I am unable to find any easy way to redefine a already defined function in another cell to test it out.
For instance
function a(b);return b+4;end
and then in next cell I would like to test instead loose the condition and have it something like
function a(b,c);return b+c;end
But I do not want to change the name because I have other dependent functions in which I call a. The reason to do this is for prototyping the best possible way to define a and obviously this wouldn't be a part of the main code.
Any way how to do this ?
Julia uses multiple dispatch and these are two different functions (or more exactly two different methods of the same function). Hence, no change of name is needed.
julia> function a(b);return b+4;end
a (generic function with 1 method)
julia> function a(b,c);return b+c;end
a (generic function with 2 methods)
julia> methods(a)
# 2 methods for generic function "a":
[1] a(b) in Main at REPL[1]:1
[2] a(b, c) in Main at REPL[2]:1
Basically, rerunning a Jupyter cell will redefine the function (if it is the same set of parameter types) so there is no problem here.
More complicated situation is when you want to change a type of a constants because they go deeper into compiler. Constants cannot change their type.
Functions are constants. Hence, if you try to assign a non-function type it will trow an error.
julia> typeof(a) <: Function
true
julia> a = 5
ERROR: invalid redefinition of constant a
Stacktrace:
[1] top-level scope at REPL[9]:1
Say I have open class C(val c:C) and I want to subclass it as class D():C(this)
This is invalid according to the compiler because 'this' is not defined in this context
Is there a way to get this to do what I want? Specifically, I'd like for D to have a constructor that can be called without any arguments and will pass the D object being constructed to C's constructor. In my case, it's fine that this object may not be fully constructed yet.
I'm open to any solutions that don't involve changing C, reflection included.
There's no straightforward solution, because it does not seem to be a good idea.
The constructor of the super class gets executed before the constructor of the class itself does (more details here). Thus passing this instance that has not been initialized at all to the super constructor in place of a valid instance may break some of the logic of the super constructor (e.g. it may expect the c's properties to have some meaningful values, but they don't).
If you need this so bad, you can try to create an instance of D first with some fake/default C, then create another D with the first one:
class D(c: C) : C(c)
fun createD(defaultC: C): D {
val firstD = D(defaultC)
return D(firstD)
}
Though this definitely does not cover all possible use cases.
Is it possible to specify a type constraint on arity of a Julia function, something like:
function foo(bar::Function{1})
...
end
This definition gives me an error:
ERROR: too many parameters for type Function
What you are asking is not possible, since a Julia function does not have well-defined arity.
Consider
f(x) = "method 1"
f(x, y) = "method 2"
after which f may be invoked in two ways:
julia> f(0)
"method 1"
julia> f(0, 0)
"method 2"
What, then, is the arity of f? If you are seeking to change behaviour of the function depending on its arity, then you need to pass in the desired arity as an additional parameter. Otherwise, the arity check can probably be left out.
Most probably, the arity constraint is needed to ensure parameter correctness. This does not need to be done in the function signature, but can be done using parameter checks at the top of the function code. One method could be:
if !any(m->length(m.sig.parameters)==2, methods(bar))
error("bar must be callable with 2 parameters")
end
More detailed checks on the signature of bar are also possible.
The declared parameter types of the function foo are idiomatically used to direct optimization through type inference and multiple dispatch and less to validate parameters.
Note that using the internal structure of MethodTable and Method types is not official Julia spec and might be subject to change in future versions of Julia.
I'm new to Scala and I'm having a problem understanding this. Why are there two syntaxes for the same concept, and none of them more efficient or shorter at that (merely from a typing standpoint, maybe they differ in behavior - which is what I'm asking).
In Go the analogues have a practical difference - you can't forward-reference the lambda assigned to a variable, but you can reference a named function from anywhere. Scala blends these two if I understand it correctly: you can forward-reference any variable (please correct me if I'm wrong).
Please note that this question is not a duplicate of What is the difference between “def” and “val” to define a function.
I know that def evaluates the expression after = each time it is referenced/called, and val only once. But this is different because the expression in the val definition evaluates to a function.
It is also not a duplicate of Functions vs methods in Scala.
This question concerns the syntax of Scala, and is not asking about the difference between functions and methods directly. Even though the answers may be similar in content, it's still valuable to have this exact point cleared up on this site.
There are three main differences (that I know of):
1. Internal Representation
Function expressions (aka anonymous functions or lambdas) are represented in the generated bytecode as instances of any of the Function traits. This means that function expressions are also objects. Method definitions, on the other hand, are first class citizens on the JVM and have a special bytecode representation. How this impacts performance is hard to tell without profiling.
2. Reference Syntax
References to functions and methods have different syntaxes. You can't just say foo when you want to send the reference of a method as an argument to some other part of your code. You'll have to say foo _. With functions you can just say foo and things will work as intended. The syntax foo _ is effectively wrapping the call to foo inside an anonymous function.
3. Generics Support
Methods support type parametrization, functions do not. For example, there's no way to express the following using a function value:
def identity[A](a: A): A = a
The closest would be this, but it loses the type information:
val identity = (a: Any) => a
As an extension to Ionut's first point, it may be worth taking a quick look at http://www.scala-lang.org/api/current/#scala.Function1.
From my understanding, an instance of a function as you described (ie.
val f = (x: Int) => x + 1) extends the Function1 class. The implications of this are that an instance of a function consumes more memory than defining a method. Methods are innate to the JVM, hence they can be determined at compile time. The obvious cost of a Function is its memory consumption, but with it come added benefits such as composition with other Function objects.
If I understand correctly, the reason defs and lambdas can work together is because the Function class has a self-type (T1) ⇒ R which is implied by its apply() method https://github.com/scala/scala/blob/v2.11.8/src/library/scala/Function1.scala#L36. (At least I THINK that's what going on, please correct me if I'm wrong). This is all just my own speculation, however. There's certain to be some extra compiler magic taking place underneath to allow method and function interoperability.
I have read the question Difference between method and function in Scala and many articles about differences between method and function. I got a feeling that a 'method' is just a "named function" defined as a method in a class, a trait or an object. A 'function' represents things like the "anonymous function" or "function literal" or "function object" in those articles. An evidence can be found in the book Programming in Scala http://www.artima.com/shop/programming_in_scala_2ed , page 141, section 8.1, "The most common way to define a function is as a member of some object. Such a function is called a method."
However, when I checked the Scala Language Reference http://www.scala-lang.org/docu/files/ScalaReference.pdf, there are concepts like named method. In page 91, Section 6.20 Return expressions: "A return expression return e must occur inside the body of some enclosing named
method or function." You can also find the term "named function" in the same page and other places.
So my question is, in Scala, do method, named method, and named function refer to the same concept? Where do you get the definition of named function?
In code List(1, 2).map(_ + 1), the original expression _ + 1 is a named method, then the method is converted into a function. What kind of function, anonymous function, function object, named function?
In my understanding, Scala only has two types of function: a named function that is a method; an anonymous function that is a function literal. Function literal is compiled into a function object of trait FunctionN for it to be used in the pure object-oriented world of Scala.
However, for a regular named funciton/method such as _ + 1 in the above code, why does Scala transform it into another function object?
At the language level, there are only two concepts,
Methods are fundamental building blocks of Scala. Methods are always named. Methods live in classes or traits. Methods are a construct native to the JVM, and thus are the same in both Scala and Java. Methods in Scala (unlike functions) may have special features: they can be abstracted over type parameters, their arguments can have default values or be implicit, etc.
Function objects are just instances of a function trait (Function1, Function2, ...). The function is evaluated when the apply method on the function object is called. There is special syntax for defining unnamed "anonymous" functions (aka, "function literals"). A function is just a value, and as such can be named (e.g., val f: (Int => Int) = (x => x)). The type A => B is shorthand for Function1[A, B].
In the linked SO question, it was mentioned that some references (like the Scala spec) use the word "function" imprecisely to mean either "method" or "function object". I guess part of the reason is that methods can be automatically converted to function objects, depending on the context. Note, however, that the opposite conversion wouldn't make sense: a method is not a first-class value that lives on the heap with its own independent existence. Rather, a method is inextricably linked to the class in which it is defined.
The answers to the linked question cover this fairly well, but to address your specific queries:
method => The thing you define with the def keyword
named method => The same, all methods have names
named function => a function that has been assigned to a value, or converted from a method. As contrasted with an anonymous function.
The difference between a method and a Function is somewhat like the difference between an int primitive and a boxed Integer in Java.
In general discussion, it's common to hear both described as being "integers". This normally isn't a problem, but you must take care to be precise wherever the distinction is relevant.
Likewise, a method will be automatically converted to a Function (and therefore an object) when your program demands it, much like boxing a primitive. So it's not entirely wrong to refer to a method as being a function.
UPDATE
So how does it work?
When you attempt to pass a method as the argument to e.g. List[A].map, the compiler will generate an inner class (with a synthetic name) that derives Function1[A,B], and an apply method that delegates to the method you originally supplied. An instance of this will then be passed as the actual argument.