Is it great to make classes as functions and declare parameter types using function types?
I'm working on a scala project and a colleague of mine who prefers a functional style and suggests a way to organize your code: defining classes as functions
Here's an example:
class FetchFeed extends (String => List[Feed]) {
def apply(url:String):List[Feed] = ???
}
If another class needs this class, it will be declared using the type String => List[Feed]
class MyWork(fetchFeed: String => List[Feed])
Then at some point pass it FetchFeed
:
val fetchFeed = new FetchFeed
val myWork = new MyWork(fetchFeed)
The pros are that we can easily mock FetchFeed
by passing a function:
val myWork = new MyWork(_ => List(new Feed))
The syntax is simple and easy to read.
But the cons are that when I see the ad MyWork
:
class MyWork(fetchFeed: String => List[Feed])
It's hard to figure out which class will be passed, not even the IDE can help me. We need to search extends (String => List[Feed])
the code base or find a place to initialize new MyWork
.
And if there is another class that extends String => List[Feed]
but is never used in MyWork
, it often confuses me.
But if we declare it with a real type:
class MyWork(fetchFeed: FetchFeed)
It's easier to jump straight to the ads. But in this case, we cannot pass functions directly, instead we need:
val fetchFeed = mock[FetchFeed]
fetchFeed.apply(any[String]) returns List(new Feed)
val myWork = new MyWork(fetchFeed)
I am struggling with two solutions. Is this a common pattern like this when you write functional style code? Are there open source projects in this style that I can get some ideas from?
source to share
The style you described is not part of it, in part because of the problems you talked about. If you're trying to achieve a functional style, you're better off just using type-aliased functions.
// Alias the function type to a meaningful name
type FetchFeed = String => List[Feed]
// Declaring an implementation
val fetchFeed: FetchFeed = url => ...
// Nice type name to work with
class MyWork(fetchFeed: FetchFeed)
// Declaring a mock is still easy
new MyWork(_ => List(new Feed))
source to share
Scala ( A => B
) functions can be thought of as equivalent to Java interfaces that define a single method apply(a: A): B
. So the style you are describing is not the same as:
- Client depends on interface
- The interface is implemented by a hidden concrete subclass
And that has been completely standard, educational Java style almost since Java was invented.
Back in the days when I was writing Java all day, I remember using the Hierarchy Show Eclipses Show shortcut to find the executable subclass.
source to share