Skip to content
Advertisement

What is the equivalent of executing multiple instance methods in functional programming in JS?

Suppose I have a class in JS with Typescript like this:

type Command = 'F' | 'B' // Forwards, Backwards

class Car {
  private x: number
  private y: number

  constructor(x: number, y: number) {
    this.x = x
    this.y = y
  }

  private reportPosition() {
    return `(${this.x}, ${this.y})`
  }

  private move(command: Command) {
    if (command === 'F') this.y++
    if (command === 'B') this.y--
  }

  execute(command: Command) {
    this.move(command)
    return this.reportPosition()
  }
}

When I create a Car instance and execute the execute method, two things happen:

  • The internal state of the instance (x, y) is updated.
  • The execute function returns a string.

Now I want to write the same thing in a more FP way, making the functions pure, but I stumble at the execute function. My approach is this:

type Command = 'F' | 'B'

type Car = {
  x: number
  y: number
}

function createCar(x: number, y: number): Car {
  return { x, y }
}

function reportPosition(car: Car) {
  return `$({car.x}, ${car.y})`
}

function move(car: Car, command: Command) {
  if (command === 'F') return createCar(car.x + 1, car.y)
  if (command === 'B') return createCar(car.x - 1, car.y)
  return car
}


function execute(car: Car, command: Command) {
  const newCar = move(car, command)
  const msg = reportPosition(newCar)
  
  return [newCar, msg]
}

My questions are the following:

  1. Since execute does two things at once, I feel I am forced to return two values from it in the function. But this feels wrong. Is this “valid” functional programming? Or would I never create such a function in the FP world and just call each of the functions inside (move, reportPosition) separately.

  2. What if the move function also had to return the information on whether the car has crashed after its move? Would I also have to return two values from that modified function: the new car instance and a boolean (indicating a crash)?

  3. Also, I used the createCar function within the move function, which is technically not allowed for pure functions, correct? What would be the best way to fix that? Pass the createCar function as an argument to move?

Thanks!

Advertisement

Answer

  1. Doing two things at once doesn’t necessarily make a function invalid functional programming (I think by “valid” you’re referring to pure functional programming). What makes a function “pure” in functional programming is that its return value is only determined by its input values and nothing else. It also does not modify any external state or variables (referred to as “free variables” or global variables, meaning a variable that is not bound in the input parameters). What you’re doing in execute can be expressed in a functional programming language trivially, for example Haskell:
execute :: Car -> Command -> (Car, String)
execute car cmd = let newCar = move car cmd in (newCar, reportPosition newCar)
  1. If move had to report additional data, you could include it in the return type and it would remain pure. However, assuming “if the car crashed” is an error state, then typically this would be modeled by returning a sum type (Maybe or Either in Haskell). Take Maybe for example: data Maybe a = Just a | Nothing, if the car crashed you could return Nothing and if it didn’t then return Just position, then anything using the move function can verify that it didn’t return Nothing.

  2. Why would you not be allowed to call createCar inside move? Neither move nor createCar are modifying any external state/variables, both are only using the inputs provided in their returns.

Re-iterating my comment in the main post, a lot of these things from Haskell that I mentioned above (e.g. Maybe) are available in libraries for JavaScript/TypeScript. For TypeScript in particular, there’s https://github.com/gcanti/fp-ts. It can be a little bit confusing sometimes, as usually there are many names that refer to the same concept. For instance, some libraries refer to Maybe as Option.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement