As long as the language you are using has a powerful type system you can easily separate data and behaviour with no problems, and some benefits. Procedural programming is then basically another name for functional programming.
For instance, in the examples above:
MoveForwardCar(car); MoveForwardBike(bike); could become
MoveForward(participant); as long as the participant type/struct/record/dataclass implemented the type IMoveForwardable.
For instance, in Scala, you can have purely data classes of a certain supertype so you can pass them to functions that know how to handle them:
sealed trait Transaction case class Deposit(amount: Money, date: LocalDate) extends Transaction case class Withdrawal(amount: Money, date: LocalDate) extends Transaction This is great because you can easily make structs immutable. And immutable types are much easier to work with because they avoid race conditions and logic errors. (Modern
Modern programming languages in general are all moving towards the benefits of: null safety, immutability, static typing).
- null safety
- immutability
- static typing.
But object orientated languages are oldolder than this movement (except Rust) and don't support immutable objects and pure functions natively yet. Thus if your language doesn't have typed structs, and because you need to call a constructor to instantiate any object, you can't do things like deepCopy() to create a copy of your immutable data to pass around without huge amounts of boilerplate code, or code generators. This idea'immutability tax' is discussed here: https://medium.com/@davidmorgan_14314/the-mutability-tax-6403d84f21c0
See also this discussion of the benefits of separating data and code: https://blog.klipse.tech/databook/2020/10/02/separate-code-data.html