Reputation: 4239
How to define some class (or type) of objects with methods etc. (like integer comparing) in Erlang?
How can I, for example, do this:
qsort([Pivot|T]) ->
qsort([X || X <- T, X =< Pivot])
++ [Pivot] ++
qsort([X || X <- T, X > Pivot]).
If I want to sort list of some objects, persons for example.
Upvotes: 5
Views: 2764
Reputation: 9225
Short answer:
You can.
Long answer:
Well, it is not convenient though. Better way would be to pass sort function to qsort (as Yasir Arsanukaev mentioned before, the same way as in lists:sort/2). But "if you put your mind to it, you can accomplish anything" as somebody used to say.
-module(persons).
-export([sort_persons/0, sort_sku/0]).
-record(person, {name, age}).
-record(sku, {item_number, price}).
-record(sortable, {lt}).
-record(object, {state, methods}).
persons_list() ->
Sortable = #sortable{lt=fun(#person{age = A1}, #person{age = A2}) -> A1 < A2 end},
[
#object{state=#person{name="John", age=38}, methods = Sortable},
#object{state=#person{name="Paul", age=25}, methods = Sortable},
#object{state=#person{name="Michael", age=23}, methods = Sortable}
].
sku_list() ->
Sortable = #sortable{lt=fun(#sku{price = P1}, #sku{price = P2}) -> P1 < P2 end},
[
#object{state=#sku{item_number="11111", price=3.54}, methods = Sortable},
#object{state=#sku{item_number="222222", price=1.58}, methods = Sortable},
#object{state=#sku{item_number="33333", price=2.31}, methods = Sortable},
#object{state=#sku{item_number="44444", price=8.41}, methods = Sortable}
].
qsort([]) ->
[];
qsort([Pivot|T]) ->
qsort([X || X <- T, (X#object.methods#sortable.lt)(X#object.state, Pivot#object.state)])
++ [Pivot] ++
qsort([X || X <- T, not (X#object.methods#sortable.lt)(X#object.state, Pivot#object.state)]).
sort_persons() ->
qsort(persons_list()).
sort_sku() ->
qsort(sku_list()).
Upvotes: -2
Reputation: 20936
Erlang has no abstract data types as such. A standard way of defining a data type is by a module which provides all access functions into the data and the user is expected not to bypass them. Examples of this in OTP are things like sets
, dict
and array
. This usually works well but you have to know what type the data is. Sometimes the structure is defined but the user is expected to "behave themselves" when working on the data, an example is ordsets
.
Note however that in all cases the data is standard immutable Erlang data which is not up-datable as in most traditional OO languages. I can only reiterate what has been said in the other answers and don't try to use OO-style in a non-OO language like Erlang, and vice-versa for that matter. The result will not be elegant and beautiful.
A final comment: that definition of quicksort while it is concise and simple is very inefficient.
Upvotes: 3
Reputation: 9686
According to your example, you just call your qsort
with appropriate list of unsorted values and get the sorted list:
some_useful_fun(X, Y) ->
% ...
Xsorted = qsort(X),
% do something with Xsorted
...
And that's all. There's no state in pure functional programming. The only state is the data passed as the arguments to functions. A function is supposed to return the same result on passed arguments in spite the number of times you call it.
In Erlang, you can map your object to a record. Consider this code:
-export([sort/0]).
-record(person,
{
name,
age
}).
persons_list() -> [
#person{name="John", age=38},
#person{name="Paul", age=25},
#person{name="Michael", age=23}
].
qsort(_Pred1, _Pred2, []) ->
[];
qsort(Pred1, Pred2, [Pivot|T]) ->
qsort(Pred1, Pred2, [X || X <- T, Pred1(X, Pivot)])
++ [Pivot] ++
qsort(Pred2, Pred2, [X || X <- T, Pred2(X, Pivot)]).
sort() ->
F1 = fun(#person{age = A1}, #person{age = A2}) ->
A1 =< A2 end,
F2 = fun(#person{age = A1}, #person{age = A2}) ->
A1 > A2 end,
qsort(F1, F2, persons_list()).
We have a record person
, which has two fields, particularly name
and age
. We also have two predicates F1
and F2
, which fit to what qsort
does. If we now call qsort/3
with these two predicates and a list of person
records, we'll get the following results:
1> c(persons).
{ok,persons}
2> persons:sort().
[{person,"Michael",23},
{person,"Paul",25},
{person,"John",38}]
3>
Which is a sorted list of person
records, you then can use in your code.
Upvotes: 2
Reputation: 36117
You can't (at least if you want to be taken seriously as an Erlang programmer whilst having Erlang code that works properly).
Erlang is a functional programming language, not an object-oriented programming language. The whole basic concept of an "object" (a collection of state with attached functions) is anathema to the functional approach (which eschews mutable state as much as possible). You could kludge together an object-like setup in a functional language -- especially an impure one like Erlang -- but the resulting code would be hard to read, hard to maintain, fragile and ugly. (Harder to read and maintain, more fragile and uglier than even OOP code written in an OOP language, hard as that may seem to be to believe.)
You'd serve your needs far better by either:
Doing half-assed OOP in a non-OOP language is generally fruitless and painful.
Upvotes: 6
Reputation: 18879
The very quick answer: You don't want to go there.
The longer answer: Erlang is not an object oriented language in the "traditional sense" of e.g., Java. But it has several mechanisms that might act as a stand-in for objects: First there is closures which can easily encode the equivalent of objects although the encoding is so unwieldy that it is hardly ever used. Rather people tend to "cherry-pick" and get the specific idea they need from OO be it incapsulation, inheritance, polymorphism and so on.
Second there are processes. A process is a seperate encapsulated entity to which you can send messages and receive answers. It is almost the same as "A class is a separate encapsulated entity to which you can use methods to operate on it". Since spawning a process is cheap, it is not a problem to use processes somewhat as OO-style objects.
Third there are parameterized modules which some people like to use as if they bring back OO-style code to the language.
Fourth, there are first-class functions. Since you can pass a function around as easily as data, you can often use this to generalize code rather than building an object hierarchy.
In conclusion: If you write Erlang in idiomatic style, you will rarely find the need for the equivalent of a 'class'.
Upvotes: 11