3 ms·
> Unfortunately, the current landscape of popular languages have equated "object programming == inheritance" in people's minds. Because OOP is somewhat equals
by ernst_klim 3y ago
> Unfortunately, the current landscape of popular languages have equated "object programming == inheritance" in people's minds.
Because OOP is somewhat equals to inheritance (or more strictly late binding + open recursion + self-polymorphism, inheritance is just one way to achieve that).
"delegating" is completely orthogonal to OOP, you can have delegates in any modular language, like ML. Saying "you need to use more delegates and less inheritance" basically equals to "you need to write less OOP code".
- crabmusket 3y ago> you can have delegates in any modular language, like ML I'm struggling to understand this, could you give an example?
- ernst_klim 3y agomodule type Repo = sig type t type user val get_user : t -> name:string -> user option val get_all_users : t -> user list end module LoggedRepo (R : Repo) : sig (* Resulting module is of type Repo plus create function *) include Repo val create : delegate:R.t -> logger:Logger.t -> t end = struct type t = { delegate : R.t; logger : Logger.t } type user = R.user let create ~delegate ~logger = { delegate; logger } let get_user repo name = Logger.debug repo.logger "Get user by name"; R.get_user repo.delegate name let get_all_users repo = Logger.debug repo.logger "Get all users"; R.get_all_users repo.delegate end In languages like C it would be harder since they don't have notion of interface and implementation, so you would have to implement that as an object-like structure of function pointers and opaque structs for state. The point is, for delegate you don't need lately bound methods and virtual dispatching, i.e. oop, only the notion of interface and implementation supported (or emulated), and then you can create implementations that wrap another implementations.
- _old_dude_ 3y agoYou still need virtual dispatch (or type pattern matching) if there is a variable which can contain either a BDRepo or a LoggedRepo(BDRepo).
- ernst_klim 3y agoNo, you don't. LocalRepo.t != Repo.t, and all the functions are purely static. LocalRepo.get_user won't work with other Repo.t, and other Repo.get_user won't work with LocalRepo.t. What you would need is to parametrize your further computation with a Repo module, as in module HttpHandler (R : Repo) : sig val handle_user : R.t -> HttpWriter.t -> username:string -> unit end = struct let handle_user repo writer ~username = match R.get_user repo username with | None -> Writer.write_status writer 404 | Some user -> Writer.write_body writer (User.to_string user) end and then to construct a handler module with a proper repo.