Stan
Stan

Reputation: 4239

Erlang: defining some class of objects with methods and fields

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

Answers (5)

Victor Moroz
Victor Moroz

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

rvirding
rvirding

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

Yasir Arsanukayev
Yasir Arsanukayev

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

JUST MY correct OPINION
JUST MY correct OPINION

Reputation: 36117

Short answer

You can't (at least if you want to be taken seriously as an Erlang programmer whilst having Erlang code that works properly).

Long answer

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:

  • learning the natural idioms and means of expressing ideas native to Erlang (LYSE is a good starting point for this preferred solution); or
  • using an object-oriented programming language for object-oriented programming.

Doing half-assed OOP in a non-OOP language is generally fruitless and painful.

Upvotes: 6

I GIVE CRAP ANSWERS
I GIVE CRAP ANSWERS

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

Related Questions