Scala parameter bracket type

I know trait Foo[T] means that T is a parameterized type. But sometimes I see trait Foo[T1,T2] or trait Foo[T1,T2,R] , I can not find anywhere to describe the value of several types inside the type bracket, could you point it out in this case? From what I assume, Foo [T1, T2] just means he defined two type parameters, he doesn’t need to take T1 and return a T2 .

When I read the playframework documentation, I was again confused about this. The documentation says:

A BodyParser [A] is basically Iteratee [Array [Byte], A], which means it gets chunks of bytes (while the web browser loads some data) and calculates a value of type A. As a result.

This explanation sounds like this: the second type parameter inside the type bracket is the return type.

I also remember that trait Function2 [-T1, -T2, +R] extends AnyRef means a function that takes T1 and T2 , returns a R

Why do they put the return type in a bracket? Does this mean that the last parameter in the bracket is the return type? Or did they just define a new type R for the return type?

+4
source share
4 answers

Multiple types within type brackets mean type parameterization on multiple types. Take for example

 trait Pair[A, B] 

This is a pair of values ​​having type A another having type B

Update:

I think you interpret too much the semantics of type parameters. A type parameterized by several parameters is simple and nothing more. The position of a particular type parameter in the type parameter list does not make it special. In particular, the last parameter in the list of type parameters does not need to indicate "return type".

The sentence from the reproducing scheme that you are quoting explains the semantics of the type parameters for this particular type. It does not generalize to other types. The same applies to Function types: here, the last type parameter means "return type". However, this is not necessary for other types. The type of Pair[A, B] above is such an example. Here B is the type of the second component of the pair. There is no concept at all of the type of return.

Parameters of the type of a parameterized type can appear anywhere in the definition of a parameterized type, where a "normal" type can appear. That is, type parameters are simply type names bound to actual types only when the instance of the parameterized type itself is.

Consider the following definition of the Tuple class:

 class Tuple[A, B](a: A, b: B) 

It is created by an instance of type Int and String as follows:

 type TupleIntString = Tuple[Int, String] 

Which essentially coincides with

 class TupleIntString(a: Int, b: String) 

For an official source, check out the Scala Language Specification . In particular, section 3.4 “Basic types and definitions of members” in section 1. The 4th marker point reads: “Basic types of a parameterized type C [T_1, ..., T_n] are basic types of C, where each occurrence is a_i of the parameter C has been replaced by the corresponding parameter type T_i. "

+4
source

From what I assume, Foo [T1, T2] just means he defined two type parameters, he doesn't need to take T1 and return T2 .

A type parameter means "I need some type, but I'm not interested in knowing what kind of concrete type it is," where "I" is the programmer who writes the code. Type parameters can be used like any other type, such as Int, String or Complex - the only difference is that they are unknown until they are used.

See type Map[A, +B] . When you first read this, you may not know what A and B are for, so you should read the documentation:

Map from type A keys to type B values.

He explains types and their meaning. To know and understand nothing more. These are just two types. You can call Map something like Map[Key, Value] , but inside the source code it is better if the type parameters have only one or two letters. This simplifies the distinction between type parameters and specific types.

This is documentation that indicates what a type parameter means. And if there is no documentation, you should take a look at the sources and find their meaning yourself. For example, you should do this with Function2 [-T1, -T2, +R] . The documentation only tells us about this:

A function of two parameters.

Well, we know that two of the three type parameters are the parameters that the function expects, but what is the third? Take a look at the sources:

def apply (v1: T1, v2: T2): R

Ah, now we know that T1 and T2 are parameters, and R is the return type.

Type parameters can also be found in method signatures, such as map:

 class List[+A] { .. def map[B](f: (A) ⇒ B): List[B] } 

This is what a map looks like when you use it with a list. A can be any type - this is the type of elements contained in the list. B is another arbitrary type. When you know what a card does, you know what B does. Otherwise, you must understand the map before. map expects a function that can convert each element of the list to another element. Since you know that A stands for list items, you can extract from yourself that B must be of type A , converted to.

To answer all your other questions: this should not be done in any answer. There are many other questions and answers on StackOverflow that can also answer your questions.

Summary

When you see some type parameters, for example, in Foo[T1, T2] , you should not start crying. Think: “Well, I have a Foo that expects T1 and T2, and if I want to know what they are doing, I need to read the documentation or sources.”

+7
source

I think your question can really be broken down into three separate issues:

What about the parameters of the multiple type for classes / features / etc.

A classic example is a map from one type of object to another. If you want the type of keys different from the type of value, but keep both common values, you need two type parameters. Thus, the map [A, B] takes the keys to the general type A and maps to the values ​​of type B. A user who wants to get the map from Bookmarks to pages will declare it as Map [Bookmark, Page]. The presence of only one type of parameters will not allow this difference.

From what I assume, Foo [T1, T2] just means he defined two types of parameters, he does not need to take T1 and return T2.

No, all type parameters are equal citizens, although they are relevant in this direction for function objects. See below.

What is this +/-?

They limit what type parameters can bind. Scala's example tutorial has a good explanation. See Section 8.2 “Change Annotations”.

What is a function in scala?

Why do they put the return type in a bracket? Does this all the last parameter in the bracket mean is the return type? Or did they just happen given a new type R for the return type?

The Scala sample tutorial explains this well in section 8.6. Functions

+4
source

Their role is a bit similar to those (i.e. a multiple type parameter) in a class, since traits are, after all, classes (without any constructor) that need to be added to some other class as mixin.

The Scala spec gives the following example for Trait with several parameters:

Consider an abstract class table that implements maps from key type A to value type B.
The class has a method specified to enter a new key / value pair into the table, and a get method that returns an optional value that corresponds to this key.
Finally, a method is used that is similar to get, except that it returns the specified default value if the table is not defined for this key. This class is implemented as follows.

 abstract class Table[A, B](defaultValue: B) { def get(key: A): Option[B] def set(key: A, value: B) def apply(key: A) = get(key) match { case Some(value) => value case None => defaultValue } } 

Here is a specific implementation of the Table class.

 class ListTable[A, B](defaultValue: B) extends Table[A, B](defaultValue) { private var elems: List[(A, B)] def get(key: A) = elems.find(._1.==(key)).map(._2) def set(key: A, value: B) = { elems = (key, value) :: elems } } 

Here is a trait that prevents parallel access to get and set operations of the parent class

 trait Synchronized Table[A, B] extends Table[A, B] { abstract override def get(key: A): B = synchronized { super.get(key) } abstract override def set((key: A, value: B) = synchronized { super.set(key, value) } } 

Note that the SynchronizedTable does not pass an argument to its superclass, Table , even if Table is defined by a formal parameter.
Also note that supercall calls in the get and set SynchronizedTable s methods statically refer to abstract methods in the Table class. This is legal if the calling method is marked as abstract override (§5.2).

Finally, the following mixin composition creates a table with a synchronized list from the string as keys and integers as values ​​and with a default value of 0:

 object MyTable extends ListTable[String, Int](0) with SynchronizedTable 

The MyTable object inherits the get and set method from SynchronizedTable .
The supercall calls in these methods are redefined to refer to the corresponding implementations in the ListTable , which is the actual supertype of the SynchronizedTable in MyTable .

+1
source

Source: https://habr.com/ru/post/1344299/


All Articles