Data is passed to a function "explicitly" whereas a method is "implicitly passed" to the object for which it was called.
Please could you explain the difference between these two ways of passing data? An example in java or c# would help.
The language Java and Python are good examples in illustrating this. In Python, the object is passed explicitly whenever a method of a class is defined:
class Example(object):
def method(self, a, b):
print a, b
# The variable self can be used to access the current object
Here, the object self is passed explicitly as the first argument. This means that
e = Example()
e.method(3, 4)
is effectively the same as calling method(e, 3, 4) if method were a function.
However, in Java the first argument is not explicitly mentioned:
public class Example {
public void method(int a, int b) {
System.out.println(a + " " + b);
// The variable this can be used to access the current object
}
}
In Java, it would be:
Example e = Example();
e.method(3, 4);
The instance e is passed to method as well but the special variable this can be used to access it.
Of course, for functions each argument is passed explicitly because each argument is mentioned in both the function definition and where the function is called. If we define
def func(a, b, c):
print a, b, c
then we can call it with func(1, 2, 3) which means all arguments are explicitly passed.
In this context a method can be considered to be a function that has access to the object it's bound to. Any properties of this object can be accessed from the method, even though they didn't appear in the signature of the function. You didn't specify a language, but let me give an example in PHP as it's pretty prevalent and easy to read even if you didn't use it.
Edit: the languages were added after I wrote this; maybe someone can translate this to one of those languages if needed.
<?php
/* Explicit passing to a function */
function f($a, b)
{
return $a + b;
}
// f(1, 2) == 3
class C
{
public $a, $b;
/* $a and $b are not in the parameter list. They're accessed via the special $this variable that points to the current object. */
public function m()
{
return $this->a + $this->b;
}
}
$o = new C();
$o->a = 1;
$o->b = 2;
//$o->m() == 3
Related
I think an extension lambda requires that you pass in the correct argument, but i seems not to do so in the following example.
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: Base.() -> Int): Int { return xl()}
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { f()}) // [1]
}
I understand that Base.h takes a function that takes a Base object as its parameter. But line [1] shows that it accepts f(), which is a function that takes no parameter. I was thinking hard about this and I prefixed it with this.f() and it still worked. Not convinced, I modified the code as follows:
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: (Base) -> Int): Int { return xl(Base())}
fun test(i:Int) = 1
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { test(1) })
}
This code works. I've run it to verify. And as you can see, b.h() accepts test(), which takes an Int. And this is contrary to the fact that Base.h() takes a Base.
Could you explain this? Thank you for reading.
Note the curly brackets around the functions that are passed in! They change everything.
In the second code, b.h { test(1) } is not passing the function test to b.h. The syntax to pass test to b.h would be b.h(::test), and that does produce an error as you would expect.
b.h { test(1) } passes a function (a lambda expression) that takes a Base as parameter, ignores that parameter, calls test(1) and returns the result. You are basically passing a function that looks like this to b.h:
fun foo(p: Base) = test(1)
You might be wondering how Kotlin knows about Base when you did not write the word Base in the call at all. Well, it can just look at the declaration of b.h, and see that { test(1) } must take a parameter of Base.
The first code snippet is a bit different, because b.h accepts a Base.() -> Int in that case. Base.() -> Int represents a function whose receiver type is Base, that is, a function func that can be called like someBaseObject.func(). Compare this to a function func that takes a Base object as parameter, which can be called like func(someBaseObject).
Again, { f() } is not passing the function f. It is a lambda expression that does nothing but calls f. In this case though, f itself can be passed to b.h (b.h(Base::f)), because it is a function with a receiver type of Base! You can do someBaseObject.f(), can't you? Passing the lambda is similar to passing an extension function that is declared like this (you're just "wrapping" f in another function):
fun Base.foo() = f()
And since the receiver of the function is Base, you are able to access other functions that has Base as the receiver (such as f) in the lambda. You can also specify the receiver (which is this) explicitly.
I have a function which has arguments that will modify multiple variables that are global. And I want the arguments to be reference arguments, so they can modify multiple global variables with the same lines of code that are modifying the arguments.
example(psuedocode):
function random(a:number, b:number, c:number):void{
a = RNG(20);
b = RNG(25);
c = RNG(30);
}
there will be two different variables passed in through a, b and c, these are global, but a, b and c are not. The goal is to not have to have identical lines of code for both separate sets of variables to set the RNG numbers.
Edit: So I suppose more explanation is in order I will probably just try to research making a wrapper or other object to add all the variables to, but I just didn't know what type of object to make and how to make it. I admit I was just being a little bit lazy in a little bit too complex creative way.
I have two sets of global variables that I want to pass into this function and set them equal to the same range of RNG as the corresponding ones in each set. The way I'm trying to do this without repeating "a = RNG(20);" twice for each one is by passing the global variables into the function as arguments, but the arguments are the variables that are having the RNG set to them. The only way this can work is if the variables are passed to the function as reference so that setting the RNG to the arguments will change the global variables.
There are two types of data in AS3:
Plain data: Boolean, String, Number, int, uint — always passed as values.
Objects: Object, Array and literally everything else — always passed as a pointer/reference rather than through copy/clone.
There's no trick, like in C/C++ there is, to pass some plain variable as a pointer to let a method modify the original and only value.
That said, there are two ways around.
Solution №1: you can pass variables indirectly, in pairs like container → variable name.
function doIt(A:Object, a:String):void
{
A[a] = RNG(20);
}
Solution №2: devise a custom wrapper class to cross the border between plain and object data.
Implementation:
package
{
public class Oint
{
public var data:int;
// Class constructor.
public function Oint(value:int = 0)
{
data = value;
}
// There's always nice to have a interface methods,
// rather than member or getter/setter, because
// you can actually link to read/write methods.
public function read():int
{
return data;
}
public function write(value:int):void
{
data = value;
}
// With this you can use Oint variables in math expressions.
public function valueOf():Object
{
return data;
}
// With this you can trace Oint variables and see their values.
public function toString():String
{
return data.toString();
}
}
}
Usage:
function random(a:Oint, b:Oint, c:Oint):void
{
a.data = RNG(20);
b.data = RNG(25);
c.data = RNG(30);
}
I noticed that I get the same effect if I define this trivial function:
fun double ( i: Int ) = i*2
and if I define a variable and assign a lambda (with an identical body) to it:
var double = { i : Int -> i*2 }
I get the same result if I call double(a) with either declaration.
This leaves me confused. When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?
When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?
Whenever you have the choice of either, you should use a fun declaration. Even with a fun you can still get a first-class callable object from it by using a function reference.
On the JVM, a fun is significantly more lightweight, both in terms of RAM and invocation overhead. It compiles into a Java method, whereas a val compiles into an instance field + getter + a synthetic class that implements a functional interface + a singleton instance of that class that you must fetch, dereference, and invoke a method on it.
You should consider a function-typed val or var only when something is forcing you to do it. One example is that you can dynamically replace a var and effectively change the definition of the function. You may also receive function objects from the outside, or you may need to comply with an API that needs them.
In any case, if you ever use a function-typed property of a class, you'll know why you're doing it.
First, if I understand you right, your question is "Why are functions first-class citizens in Kotlin -- And when to use them as such?", right?
Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. You can operate with functions in any way that is possible for other non-function values. (see here)
As stated in the docs, one use case are higher-order functions. As a first step, I will leave the wikipedia link here: https://en.wikipedia.org/wiki/Higher-order_function
Basically, a higher-order function is a function that takes functions as parameters, or returns a function.
This means that a higher-order function has at least one parameter of a function type or returns a value of a function type.
Following a short example of a higher-order function that receives a parameter of function type (Int) -> Boolean:
fun foo(pred: (Int) -> Boolean) : String = if(pred(x)) "SUCCESS" else "FAIL"
This higher-order function can now be called with any (Int) -> Boolean function.
The docs also state ... [can be used] in any way that is possible for other non-function values.
This means that you can, for example, assign different functions to a variable, depending on your current context.
For example:
// This example is verbose on purpose ;)
var checker: (Int) -> Boolean
if (POSITIVE_CHECK) {
checker = { x -> x > 0 } // Either store this function ...
} else {
checker = { x -> x < 0 } // ... or this one ...
}
if (checker(someNumber)) { // ... and use whatever function is now stored in variable "checker" here
print("Check was fine")
}
(Code untested)
You can define variable and assign it lambda when you want change behaviour for some reason. For example, you have different formula for several cases.
val formula: (Int) -> Int = when(value) {
CONDITION1 -> { it*2 }
CONDITION2 -> { it*3 }
else -> { it }
}
val x: Int = TODO()
val result = formula(x)
If you simply need helper function, you should define it as fun.
If you pass a lambda as a parameter of a function it will be stored in a variable. The calling application might need to save that (e.g. event listener for later use). Therefore you need to be able to store it as a variable as well. As said in the answer however, you should do this only when needed!
For me, I would write the Lambda variable as followed:
var double: (Int) -> Int = { i -> //no need to specify parameter name in () but in {}
i*2
}
So that you can easily know that its type is (i: Int) -> Int, read as takes an integer and returns an integer.
Then you can pass it to somewhere say a function like:
fun doSomething(double: (Int) -> Int) {
double(i)
}
I'd like to know what's the default approach for those times when you need a variable to have been set in order for a given method/another variable initialization to work.
Like this:
Everything works if I initialize var A after var B. But not the other way around. I wrote the constructor, so I'll do that myself, but I'm not really sure where the code that tests for var B's existence should be. Or even if it should exist at all, for I have written the constructor and I initialize the values the order I see fit, but I feel it's a little insecure because it is not very robust in case anything changes.
Mind you, I'm talking about instance variables, if that helps.
FA
The answer can be influenced by the reason why a must be set before b.
Explicit Object Dependencies
If the reason is that b depends upon a, then the simplest thing to do is to make that dependency explicit at the time that b is created. For example, if a and b were objects then:
var a = new A(...);
var b = new B(a, ...);
var op = new Operation(b);
op.perform();
In this way, it is not possible to initialize the objects out of order. Note that A and B could be newly introduced wrapper objects that contain the original operation parameters.
Fluent Interface
If the reason is that the operation itself must know the value of a in order to perform some configuration in preparation for the arrival of b, then the operation constructor could be replaced by a fluent interface:
Operation op = Operation.withA(a).withB(b);
op.perform();
We must take care to define this fluent interface in such a way that withB can only be called after withA has been called. For example:
public class Operation {
private final C _c;
private final B _b;
private Operation(C c, B b) {
_c = c;
_b = b;
}
public static BStep withA(final A a) {
return new BStep() {
public Operation withB(B b) {
C c = setUpStateDependentUponA(a);
return new Operation(c, b);
}
};
};
public interface BStep {
Operation withB(B b);
}
public void perform() {
// do something with _c and _b
}
}
Here, C has been introduced to capture that state that is dependent upon a alone prior to the arrival of b. Note how the constructor of Operation is not visible to client code and that withB cannot possibly be called until after withA has been called.
I check before each time I access the variable, but if it is an instance variable and you initialize B in the constructor you should be safe. I use something like-
if (isset(var B)
{ do something with var A }
else
{ error handler }
or
try
{
if (isset(var B))
do something with a;
else
throw new Exception("attribute B has not been set.");
}
catch (Exception $e)
{
echo $e->getMessage();
return NULL;
}
If a constructor takes its parameters as a vararg (...) it seems to be impossible to create a subclass that will just pass on that vararg to the superclass.
There is a related question with fix for this same situation for normal functions: Wrapping a Vararg Method in ActionScipt but I cannot get that to work with a super call.
base class:
public class Bla
{
public function Bla(...rest)
{
trace(rest[0]); // trace the first parameter
}
}
subclass:
public class Blie extends Bla
{
public function Blie(...rest)
{
// this is not working, it will
// pass an array containing all
// parameters as the first parameters
super(rest);
}
}
if I now call
var b1 = new Bla('d', 'e');
var b2 = new Blie('a', 'b', 'c');
I get the output
d
a,b,c
And I want it to print out:
d
a
Aside from actually moving the handling of the parameters to the subclass or shifting it off to a separate initializer method, does anyone know how to get the super call right?
There's unfortunately no way to call the super constructor with ... args. If you remove the super() call, it will be called by the compiler (with no arguments). arguments is also not accessible from constructors.
If you can change the method signatures, you modify the arguments to accept an Array rather than ... args. Otherwise, as you mentioned, you could move it into an initializer method.
You may use a statement like this:
override public function doSomething(arg1:Object, ...args):void {
switch(args.length) {
case 0: super.doSomething(arg1); return;
case 1: super.doSomething(arg1, args[0]); return;
case 2: super.doSomething(arg1, args[0], args[1]); return;
}
}