Submitting a Structural Type to Scala

I am trying to better understand the structure of sending a type. For example, suppose I have an iterable object using the summary method, which calculates the average. So o.summary() gives the average of the list. I would like to use a structural type dispatcher to enable summary(o) .

  • Is there a set of best practices regarding o.summary() vs. summary(o) ?
  • How scala resolves summary(o) if I have a summary(o: ObjectType) and summary(o: { def summary: Double}) method
  • How is sending a structural type different from multi-mode or generic functions?

Michael Galpin gives the following description of the dispatch structure type :


Structural types - This is Scala's version of the "responsive" programming version, as shown in many dynamic languages. So that,

 def sayName ( x : { def name:String }){ println(x.name) } 

Then, any object with a method called name that takes no parameters and returns a string can be passed sayName:

 case class Person(name:String) val dean = Person("Dean") sayName(dean) // Dean 

+4
source share
3 answers

-- 1. In your example, I would not use the summary(o) version, since this is not a very object-oriented programming style. When you call o.summary (you can remove the brackets since it has no side effects), you request the summary o property. When you call summary(o) you pass o method that computes the summary o . I think the first approach is more enjoyable :).

I did not use scheduling of the structural type, but I assume that it is best suited (on a large system) for the case when you have to write an interface just because one method needs a type that has a specific method, Sometimes creating this interface and forcing clients its implementation may be inconvenient. Sometimes you want to use a client defined in another API that matches your interface but does not explicitly implement it. So, in my opinion, scheduling a structural type is a good way to make an adapter template implicit (it saves on a template, yay!).

-- 2. Apparently, if you call summary(o) and o has an ObjectType , it calls the summary(o: ObjectType) (which makes sense). If you call summary(bar) , in which bar does not matter ObjectType , two things can happen. The call compiles if bar has the summary() method of the right signature and name or otherwise, the call does not compile.

Example:

 scala> case class ObjectType(summary: Double) defined class ObjectType scala> val o = ObjectType(1.2) o: ObjectType = ObjectType(1.2) scala> object Test { | def summary(o: ObjectType) { println("1") } | def summary(o: { def summary: Double}) { println("2")} | } defined module Test scala> Test.summary(o) 1 

Unfortunately, something like the following does not compile due to type erasure:

 scala> object Test{ | def foo(a: {def a: Int}) { println("A") } | def foo(b: {def b: Int}) { println("B") } | } :6: error: double definition: method foo:(AnyRef{def b(): Int})Unit and method foo:(AnyRef{def a(): Int})Unit at line 5 have same type after erasure: (java.lang.Object)Unit def foo(b: {def b: Int}) { println("B") } 

-- 3. In a certain sense, scheduling of a structural type is more dynamic than general methods, and also serves a different purpose. In the general method, you can say either: a. I want something like; b. I want something of type that is a subtype of A; with. I'll take something that is supertype B; e. I'll take something that has an implicit type C conversion. All of them are much more strict than just "I want a type that has the foo method with the correct signature." In addition, scheduling of a structural type uses reflection, since they are implemented by erasing the type.

I don’t know much about multimethods, but looking at the Wikipedia article , it seems that dots can be achieved in Scala using a pattern matching. Example:

 def collide(a: Collider, b: Collider) = (a, b) match { case (asteroid: Asteroid, spaceship: Spaceship) => // ... case (asteroid1: Asteroid, asteroid2: Asteroid) => // ... ... 

Again, you can use a structural type dispatcher - def collide(a: {def processCollision()}) , but it depends on the design solution (and I would create an interface in this example).

-- Flaviu Cipcigan

+3
source

Structural data types are not really all that useful. This does not mean that they are useless, but they are definitely niche.

For example, you can write a general test case for " size ". You can do it as follows:

 def hasSize(o: { def size: Int }, s: Int): Boolean = { o.size == s } 

This can then be used with any object that implements the size method, regardless of its class hierarchy.

Now they are NOT structural type dispatchers. They do NOT relate to scheduling, but to determine the type.

And Scala is always an object oriented language. You must call methods on objects. Functional calls are actually calls to the apply method. Things like " println " are just objects imported into scope.

+3
source

I think you asked what Scala does with a structural type call. He uses reflection. For example, consider

 def repeat(x: { def quack(): Unit }, n: Int) { for (i <- 1 to n) x.quack() } 

A call to x.quack() compiled into a search for the quack method, and then a call using Java reflection. (You can verify this by looking at byte codes using javap. Find a class with a funny name, such as Example$$anonfun$repeat$1 )

If you think about it, this is not surprising. There is no way to make a regular method call because there is no common interface or superclass.

So, other respondents were absolutely right that you do not want to do this if you do not want to. The cost is very high.

0
source

All Articles