clojure: can I define an implicit conversion possility? - clojure

I have a protocol called IExample and I define a record type A that implements it:
(defprotocol IExample
(foo [this] "do something")
(bar [this] "do something else"))
(defrecord A [field1 field2]
IExample
(foo [this]
(+ field1 field2))
(bar [this]
(- field1 field2)))
Let's say I want to extend another (basic) type B to implement this protocol, but I know how to convert from B to A:
(defn B-to-A
"converts a B object to an A object"
[Bobj] ...)
because I have this conversion, I can delegate all calls of the IExample protocol
on a B to the IExample protocol on an A by delegating them:
(extend B
IExample {
:foo (fn [this] (foo (B-to-A this)))
:bar (fn [this] (bar (B-to-A this)))})
This, however, seems as an awful lot of boilerplate (especially for bigger protocols)
that is not clojure-idiomatic.
How can I tell clojure just to implicitly convert B to A every time
an IExample function is called on a B object, using the B-to-A function?

As far as the boilerplate is concerned, you can write some macro to write all that boilerplate for you. On the other hand, you could have a second look at your design here.
What we have here is 3 things (types): A, B and IExample. And then we have 2 relationships between these things: 1) a-to-example : A -> IExample 2) b-to-a : B -> A and from this we can get 3rd relationship by using composition i.e compose b-to-a with a-to-example : B -> IExample. Now if we try to move this design to protocols we will find that it is not a simple translation because protocols won't directly compose as discussed in the above design, instead we can use an intermediate protocol IToExample like shown below:
(defprotocol IExample
(foo [this] "do something")
(bar [this] "do something else"))
(defprotocol IToExample
(to-example [this] "convert to IExample"))
(defrecord A [field1 field2]
IExample
(foo [this]
(+ field1 field2))
(bar [this]
(- field1 field2))
IToExample
(to-example [this] this))
(deftype B [])
(defn b-to-a [b] (A. ....))
(extend B
IToExample {:to-example b-to-a})
What we did that we represented the -> IExample in our design as the IToExample protocol with one function. So we got:
a-to-example : A -> IExample by implementing IToExample for A
b-to-a : B -> A by a normal function
compose b-to-a with a-to-example : B -> IExample by implementing IToExample for B and using b-to-a.

It depends. If you look at the clojure core seq functions, you may notice that the ISec interface is only 4 methods, and that the whole "public" sequence library is defined by (many more) functions that call (some-internal-function (seq argument)) - and they tend to be explicitly documented as doing that too. Conceptually, there's an protocol like your IExample interface, and an additional protocol that describes the seq function to convert from some type to something implementing ISeq.
This is an especially useful strategy if the datatype only needs to implement a couple of methods (so IExample can be small) and the number of algorithms acting on the protocol is large (since you can write all of those in terms of regular functions).

Related

Instance variable assigned in initializer wrongly inferred as nilable

Using Crystal 0.25.1 the type of the instance variable #foo in this example is inferred to be nil-able even though it can never be nil:
class Foo
end
class Bar
def initialize(foo : Foo? = nil)
#foo = foo || Foo.new
end
end
p typeof(Bar.new.#foo) # => (Foo | Nil)
I know that I can declare #foo : Foo at the class level, to work around the issue, but why can't the Crystal compiler infer that #foo can never be nil on its own?

Object oriented programming in Haskell

I'm trying to get an understanding of object oriented style programming in Haskell, knowing that things are going to be a bit different due to lack of mutability. I've played around with type classes, but my understanding of them is limited to them as interfaces. So I've coded up a C++ example, which is the standard diamond with a pure base and virtual inheritance. Bat inherits Flying and Mammal, and both Flying and Mammal inherit Animal.
#include <iostream>
class Animal
{
public:
virtual std::string transport() const = 0;
virtual std::string type() const = 0;
std::string describe() const;
};
std::string Animal::describe() const
{ return "I am a " + this->transport() + " " + this->type(); }
class Flying : virtual public Animal
{
public:
virtual std::string transport() const;
};
std::string Flying::transport() const { return "Flying"; }
class Mammal : virtual public Animal
{
public:
virtual std::string type() const;
};
std::string Mammal::type() const { return "Mammal"; }
class Bat : public Flying, public Mammal {};
int main() {
Bat b;
std::cout << b.describe() << std::endl;
return 0;
}
Basically I'm interested in how to translate such a structure into Haskell, basically that would allow me to have a list of Animals, like I could have an array of (smart) pointers to Animals in C++.
You just don't want to do that, don't even start. OO sure has its merits, but “classic examples” like your C++ one are almost always contrived structures designed to hammer the paradigm into undergraduate students' brains so they won't start complaining about how stupid the languages are they're supposed to use†.
The idea seems basically modelling “real-world objects” by objects in your programming language. Which can be a good approach for actual programming problems, but it only makes sense if you can in fact draw an analogy between how you'd use the real-world object and how the OO objects are handled inside the program.
Which is just ridiculous for such animal examples. If anything, the methods would have to be stuff like “feed”, “milk”, “slaughter”... but “transport” is a misnomer, I'd take that to actually move the animal, which would rather be a method of the environment the animal lives in, and basically makes only sense as part of a visitor pattern.
describe, type and what you call transport are, on the other hand, much simpler. These are basically type-dependent constants or simple pure functions. Only OO paranoia&ddagger; ratifies making them class methods.
Any thing along the lines of this animal stuff, where there's basically only data, becomes way simpler if you don't try do force it into something OO-like but just stay with (usefully typed) data in Haskell.
So as this example obviously doesn't bring us any further let's consider something where OOP does make sense. Widget toolkits come to the mind. Something like
class Widget;
class Container : public Widget {
std::vector<std::unique_ptr<Widget>> children;
public:
// getters ...
};
class Paned : public Container { public:
Rectangle childBoundaries(int) const;
};
class ReEquipable : public Container { public:
void pushNewChild(std::unique_ptr<Widget>&&);
void popChild(int);
};
class HJuxtaposition: public Paned, public ReEquipable { ... };
Why OO makes sense here? First, it readily allows us to store a heterogeneous collection of widgets. That's actually not easy to achieve in Haskell, but before trying it, you might ask yourself if you really need it. For certain containers, it's perhaps not so desirable to allow this, after all. In Haskell, parametric polymorphism is very nice to use. For any given type of widget, we observe the functionality of Container pretty much reduces to a simple list. So why not just use a list, wherever you require a Container?
Of course, in this example, you'll probably find you do need heterogeneous containers; the most direct way to obtain them is {-# LANGUAGE ExistentialQuantification #-}:
data GenericWidget = GenericWidget { forall w . Widget w => getGenericWidget :: w }
In this case Widget would be a type class (might be a rather literal translation of the abstract class Widget). In Haskell this is rather a last-resort thing to do, but might be right here.
Paned is more of an interface. We might use another type class here, basically transliterating the C++ one:
class Paned c where
childBoundaries :: c -> Int -> Maybe Rectangle
ReEquipable is more difficult, because its methods actually mutate the container. That is obviously problematic in Haskell. But again you might find it's not necessary: if you've substituted the Container class by plain lists, you might be able to do the updates as pure-functional updates.
Probably though, this would be too inefficient for the task at hand. Fully discussing ways to do mutable updates efficiently would be too much for the scope of this answer, but such ways exists, e.g. using lenses.
Summary
OO doesn't translate too well to Haskell. There isn't one simple generic isomorphism, only multiple approximations amongst which to choose requires experience. As often as possible, you should avoid approaching the problem from an OO angle alltogether and think about data, functions, monad layers instead. It turns out this gets you very far in Haskell. Only in a few applications, OO is so natural that it's worth pressing it into the language.
†Sorry, this subject always drives me into strong-opinion rant mode...
&ddagger;These paranoia are partly motivated by the troubles of mutability, which don't arise in Haskell.
In Haskell there isn't a good method for making "trees" of inheritance. Instead, we usually do something like
data Animal = Animal ...
data Mammal = Mammal Animal ...
data Bat = Bat Mammal ...
So we incapsulate common information. Which isn't that uncommon in OOP, "favor composition over inheritance". Next we create these interfaces, called type classes
class Named a where
name :: a -> String
Then we'd make Animal, Mammal, and Bat instances of Named however that made sense for each of them.
From then on, we'd just write functions to the appropriate combination of type classes, we don't really care that Bat has an Animal buried inside it with a name. We just say
prettyPrint :: Named a => a -> String
prettyPrint a = "I love " ++ name a ++ "!"
and let the underlying typeclasses worry about figuring out how to handle the specific data. This let's us write safer code in many ways, for example
foo :: Top -> Top
bar :: Topped a => a -> a
With foo, we have no idea what subtype of Top is being returned, we have to do ugly, runtime based casting to figure it out. With bar, we statically guarantee that we stick to our interface, but that the underlying implementation is consistent across the function. This makes it much easier to safely compose functions that work across different interfaces for the same type.
TLDR; In Haskell, we compose treat data more compositionally, then rely on constrained parametric polymorphism to ensure safe abstraction across concrete types without sacrificing type information.
There are many ways to implement this successfully in Haskell, but few that will "feel" much like Java. Here's one example: we'll model each type independently but provide "cast" operations which allow us to treat subtypes of Animal as an Animal
data Animal = Animal String String String
data Flying = Flying String String
data Mammal = Mammal String String
castMA :: Mammal -> Animal
castMA (Mammal transport description) = Animal transport "Mammal" description
castFA :: Flying -> Animal
castFA (Flying type description) = Animal "Flying" type description
You can then obviously make a list of Animals with no trouble. Sometimes people like to implement this via ExistentialTypes and typeclasses
class IsAnimal a where
transport :: a -> String
type :: a -> String
description :: a -> String
instance IsAnimal Animal where
transport (Animal tr _ _) = tr
type (Animal _ t _) = t
description (Animal _ _ d) = d
instance IsAnimal Flying where ...
instance IsAnimal Mammal where ...
data AnyAnimal = forall t. IsAnimal t => AnyAnimal t
which lets us inject Flying and Mammal directly into a list together
animals :: [AnyAnimal]
animals = [AnyAnimal flyingType, AnyAnimal mammalType]
but this is actually not much better than the original example since we've thrown away all information about each element in the list except that it has an IsAnimal instance, which, looking carefully, is completely equivalent to saying that it's just an Animal.
projectAnimal :: IsAnimal a => a -> Animal
projectAnimal a = Animal (transport a) (type a) (description a)
So we may as well have just gone with the first solution.
Many other answers already hint at how type classes may be interesting to you. However, I want to point out that in my experience, many times when you think that a typeclass is the solution to a problem, it's actually not. I believe this is especially true for people with an OOP background.
There's actually a very popular blog article on this, Haskell Antipattern: Existential Typeclass, you might enjoy it!
A simpler approach to your problem might be to model the interface as a plain algebraic data type, e.g.
data Animal = Animal {
animalTransport :: String,
animalType :: String
}
Such that your bat becomes a plain value:
flyingTransport :: String
flyingTransport = "Flying"
mammalType :: String
mammalType = "Mammal"
bat :: Animal
bat = Animal flyingTransport mammalType
With this at hand, you can define a program which describes any animal, much like your program does:
describe :: Animal -> String
describe a = "I am a " ++ animalTransport a ++ " " ++ animalType a
main :: IO ()
main = putStrLn (describe bat)
This makes it easy to have a list of Animal values and e.g. printing the description of each animal.

How to map method name X to method name Y in Scala like in List

Referring to the answer of the following question:
List.empty vs. List() vs. new List()
How did the developers of Scala map the method apply[A](xs: A*) defined in the List object, to be usable as List[A](cs: A*)?
Also how did they translate aListInstance(n: Int) to the method apply(n: Int) (which returns the n'th element of the list) defined in the List class?
In both cases I'm calling the apply() methods without writing .apply() in my code. How does that work?
It works because the Scala Language Specification says so.
foo(bar)
is translated to
foo.apply(bar)
just like
foo.bar = baz
is translated to
foo.bar_=(baz)
and
foo(bar) = baz
is translated to
foo.update(bar, baz)
and
foo bar baz
is translated to
foo.bar(baz)
and
foo bar_: baz
is translated to
baz.bar_:(foo)
and so on and so forth.

Call function of protocol masquerading as generic superclass/interface?

E.g.,
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Superclass ;; a java abstract class
(foo [x]
(println "superclass"))
Subclass ;; a concrete java class implementing the above abstract class
(foo [x]
(foo (cast Superclass x))))
If calling
(foo subclass-instance)
I would get a stack overflow obviously, but is there some way to accomplish what I'm trying to do here, i.e., call the same function but masquerade as the generic superclass/interface?
Update: A clearer example demonstrating a use case for what I'm asking:
(defprotocol P
(extract-properties-into-map [self]))
(extend-protocol P
PropertyContainer ;; abstract class
(extract-properties-into-map
[this]
(into {} (for [[k v] (.getProperties this)] [(keyword k) (read-string v)])))
Foo
(extract-properties-into-map
[this]
(assoc {:properties (extract-properties-into-map
^PropertyContainer this)} ;; this is where it falls apart
:foo-type (.getFooType this)
:foo-permissions (.getPermissions this)
:foo-whatever (.getWhatever this))))
The problem with cast is that it works like a type assertion, just throwing an exception if your object does not satisfy the is-a relationship.
(defn cast
"Throws a ClassCastException if x is not a c, else returns x."
{:added "1.0"
:static true}
[^Class c x]
(. c (cast x)))
There is no new interface being returned to dispatch in a different function, i.e. you have a stack overflow.
I'm not sure what it means to be extending a protocol for an Interface? Since you're providing an implementation I guess you should define a type first and extend the protocol on that super-type.
EDIT: A slightly better answer based on delegating-proxy from https://gist.github.com/michalmarczyk/1715851
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Number ;; a java abstract class
(foo [x]
(println "superclass:" x))
Integer ;; a concrete java class implementing the above abstract class
(foo [x]
(foo (delegating-proxy x [Number] []))))
Called with
(foo (Integer. 1))
=> superclass: 1
While it does as the question asked and it now wraps the original x. Depending on the requirements, it might be better to delegate foo to a function not included in the protocol, maybe superfoo
(defn superfoo [x] { :byte (.byteValue x) })
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Number ;; a java abstract class
(foo [x]
(superfoo x))
Integer ;; a concrete java class implementing the above abstract class
(foo [x]
(merge (superfoo x) { :f (.floatValue x)})))
I think the underlying issue is Protocols do not know about class inheritance. Also, seems like Clojure should have a wait to coerce an object to a type. Type hints do not work in this case.

How do I use Clojure memfn with a Java constructor?

I want to use a Java constructor as a first-class Clojure function. My use-case is to transform a sequence of strings into a sequence of Java objects that have a constructor with a single string:
Simple Java object:
public class Foo {
public Foo(String aString){
// initialize the Foo object from aString
}
}
And in Clojure I want to do this:
(defn make-foo (memfn Foo. a-string))
(apply make-foo '("one" "two" "shoe"))
The apply should return a list of Foo objects created from Strings, but I'm getting this:
IllegalArgumentException No matching method found: org.apache.hadoop.io.Text. for class java.lang.String clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)
Don't bother. memfn is practically deprecated in favor of the anonymous function literal, with which you can also invoke constructors, e.g., #(Foo. %).
Also, your apply call is going to try to invoke make-foo once with three string args. You probably instead want:
(map #(Foo. %) ["one" "two" "three"])