Scala name passing parameter and value passing parameter

Posted by theBond on Thu, 13 Jan 2022 08:57:12 +0100

Scala name passing parameter and value passing parameter

  • Call by name parameter
  • Call by value parameter

In Scala, when a parameter calls a function by passing a value, it evaluates the passed in expression or parameter value once before calling the function. However, when calling a function by name, the value of the passed in expression will be recalculated when accessing parameters inside the function. The example here shows their differences and syntax. That is, when a named parameter is used by a function, it will be recalculated and may be calculated multiple times.

Value transfer parameter

Changes to formal parameters are not passed back to the caller. Any modification to the internal parameter variables of the called function or method only affects the separate storage location and will not be reflected in the arguments in the calling environment. This method is also called a value passing call.

grammar

def callByValue(x: Int)

example

The following is a Scala program called by function passing value

object GFG {
	// Main method
	def main(args: Array[String])  {
		// Define function
		def ArticleCounts(i: Int) {
			println("Tanya did article on day one is 1 - Total = " + i)
			println("Tanya did article on day two is 1 - Total = " + i)
			println("Tanya did article on day three is 1 - Total = " + i)
			println("Tanya did article on day four is 1 - Total = " + i)
		}

		var Total = 0;
		
		// function call
		ArticleCounts {
			Total += 1 ; Total
		}
	}
}

output

Tanya did article on day one is 1 - Total = 1
Tanya did article on day two is 1 - Total = 1
Tanya did article on day three is 1 - Total = 1
Tanya did article on day four is 1 - Total = 1

Here, by using the function value passing call mechanism in the above program, the total number of articles does not increase.

Named parameter

The named calling mechanism passes the code block to the function call, and the code block is compiled, executed and evaluated. The message will print first and then return a value.

grammar

def callByName(x: => Int)

example

The following is a Scala program called by function name

object main {
	// Main method
	def main(args: Array[String]) {
		// Defining a named calling function
		def ArticleCounts(i: => Int) {
			println("Tanya did articles on day one is 1 - Total = " + i)
			println("Tanya did articles on day two is 1 - Total = " + i)
			println("Tanya did articles on day three is 1 - Total = " + i)
			println("Tanya did articles on day four is 1 - Total = " + i)
		}

		var Total = 0;
		
		// function call
		ArticleCounts {
			Total += 1 ; Total
		}
  }
}

output

Tanya did articles on day one is 1 - Total = 1
Tanya did articles on day two is 1 - Total = 2
Tanya did articles on day three is 1 - Total = 3
Tanya did articles on day four is 1 - Total = 4

Here, the total number of articles will increase by using the function passing and calling mechanism in the above program.

For a named parameter, the parameter value is calculated each time it is used. If they are not used, they are not calculated at all.
This is similar to replacing a named parameter with a passed expression. They are the opposite of the value passing parameters. To create a named parameter, simply prefix its type with = >.

The advantage of named parameters is that they will not be evaluated if they are not used in the function body. On the other hand, the advantage of value passing parameters is that they are evaluated only once.

Here is an example of how we implement a while loop:

def whileLoop(condition: => Boolean)(body: => Unit): Unit =
  if (condition) {
    body
    whileLoop(condition)(body)
  }

var i = 2

whileLoop (i > 0) {
  println(i)
  i -= 1
}  // prints 2 1

The while loop method uses multiple parameter lists to get the condition and body of the loop. If condition is true, execute body and call while loop recursively. If condition is false, body will never be evaluated because we append = > to the type of body.

Now when we pass I > 0 as our condition and println (I); As a body, I - = 1 behaves like a standard while loop in many languages.

If the parameter is a calculation intensive or long-running code block, such as obtaining a URL, the ability to delay the calculation of the parameter until it is used can help improve performance.

summary

call by name in Scala is only supported on the caller, while lazy is only supported on the definer.

  • call by name parameter
    • Parameters are almost simply replaced into the body of the function in any (not computed) form when the function is called. This means that it may need to be calculated multiple times in vivo.
  • call by need on demand
    • Parameters are not evaluated when the function is called, but are required when used for the first time, and then the values are cached. Then, whenever the parameter is needed again, the cached value is looked up. Using lazy val in scala can do this
  • call by value
    • The parameters are evaluated when the function is called, even if the function does not end up using them. Usually this way.

Yes, lazy, why use other methods?

Unless you have reference transparency, deferred calculations are difficult to reason because you need to determine exactly when to calculate your lazy value. Since Scala is built to interoperate with Java, it needs to support imperative, side-effect programming. Therefore, in many cases, using lazy in scala is not a good idea.

In addition, lazy has a performance overhead: you need to have an additional indirect check to see if the value has been calculated. In Scala, this means more objects, which puts more pressure on the garbage collector.

Finally, in some cases, inert calculations leave a "space" leak. For example, in Haskell, it is a bad idea to collapse the large list on the right by adding a large number of numbers, because Haskell will build a large number of lazy calls to (+) before calculating them (in fact, you only need it to have an accumulator. A famous example of space problems even in a simple context is foldr vs foldl vs foldl.

other

As shown above, the more common way to use named parameters is as follows:

def foo(x: => Int) = {
  lazy val _x = x
  // The following are used_ x
}

This simple function only calculates x once when it will be used, and uses lazy storage, which means that it will be used later_ X, the value of X will not be calculated repeatedly if the function is not used_ x. Then x is not evaluated.

In this paper, evaluated is interpreted as calculation, which is easy to understand.

Nuggets https://juejin.cn/post/7052590747635646472

Topics: Scala Back-end