Reasoning about "inheritance"

so i’ve been away from rescript for a while, delving into a typescript project for work for some time. coming back, i’m having a hard time getting back into the proper mindset.

right now, i’m struggling with reasoning about this:

let’s say i have a TcpServer and TcpConn module. the TcpServer has a listen function that creates a tcp socket and starts accepting connections. for each connection, it creates a TcpConn (with its respective socket attached to it somehow in some opaque type). so far no real problems.

ok, let’s say i want to extend both of these to HttpServer and HttpConn effectively. the only ways i can come up with are either wrapping the TcpServer in the HttpServer module and effectively reimplementing everything or creating a functor (i haven’t fully wrapped my head around this).

how would you go about doing this? if some functionality is added to the TcpServer module, it should be “inherited” automatically into the HttpServer, as, effectively, an HttpServer is also a TcpServer.

thoughts?

To start, an http server and a tcp server are two different things and probably have two different implementations, what are you trying to achieve my extending it?

Incorrect inference about the “is-a” relationship is a pitfall of the class inheritance syntax. The HTTP protocol “consumes” TCP’s interface, not as part of it. In layered architecture, we call it backend and frontend. Similar to the server-client relationship.

1 Like

I mean this is an interesting discussion in and of itself, I guess you could theoretically build an UDP HTTP server. I still don’t think the “has-a” relationship is the correct way to go (conceptually, in ReScript it’s not really the same choice)

it might actually be an incorrect understanding of the relationship between the two - it’s not like inheritance is not misused (by me and everyone else) in more object-oriented languages for the sake of simplicity. it usually works out ok. in more worldly terms, the concept holds true though; an http server is a tcp server in the same way that a coffee machine is an electrical machine (drinking my coffee, so first thing that came to mind).

either way, how do you usually go about modeling relationships like these in ReScript? I ended up setting up the http part upon acceptance of the connection, so the state ended up as part of captures for a closure. that is basically the same as creating an object, just using a different syntax.

Then you can use mixins for simple cases. The only difference is that there is no implicit dispatch table and you manage it yourself.

module Circle = {
  include Shape

  let method = () => {
    let _ = Shape.method // you can override
  }
}

But as this gets messy quickly, I’d follow the wisdom of our predecessors. Composition over inheritance

4 Likes

Thanks, I looked into that but it seems to be heavily discouraged. It works pretty well, except that you can’t e.g. add fields to types, so unless you want to manage any state whatsoever, you probably want to use composition anyway - as you rightly point out.

The other approach would possibly be functors, but I think given that rescript isn’t oo, i’d probably want to throw the is-a thinking out the window anyway.

2 Likes

Hi,

I would do it like this: ReScript Playground