Live data from Hacker News

John Carmack on Functional Programming in C++ (2018)

sevangelatos.com

101–110 of 179 posts

Re: John Carmack on Functional Programming in C++ (2018)

#101
post #61

Earlier quoted context omitted.

> adding new business logic to a process, Adding logic is the smallest part of the problem: adding types, that aren't constrained to represent the smallest set of values needed for the problem at hand, that's the biggest problem. This 'looseness' doesn't show up as a compilation error and looks on the surface to be just fine. Then the real-world comes along and creates a value that should never exist and the code fal…

> ...you tend to find the code writes itself. ...in theory. The problem is usually that you had already spent a lot more time designing all your type constraints before "the code can write itself", then it would have been to just sit down and write some code to get the damn thing working first. And at least IME, spending so much time upfront without any visible process results in too rigid "over-architected" systems…

You're mischaracterising what I am saying. You're talking about 'over architected' systems. That doesn't represent how I work or anything I am advocating. Types are composable, when you design a system or sub-system, make sure those types are constrained to represent the smallest set of values the sub-system needs. Then those types can be composed with other types to make larger systems. You start small and build out with composition, you don't need to architect some epic type-schema in one sitting.

It's really not that hard to do (well in FP languages anyway) and ends up improving throughput for any coding task due to the reduced need to constatly check if something does what you think it should do.

> The best solution is usually to not give in to either extremes, but find a well balanced approach somewhere in the middle where you have some sane restrictions designed into the types to prevent the most obvious bugs.

That isn't the best solution, it's a solution. As I mentioned in another comment [1], it's about risk, and how much you're willing to take on as a developer and as a team. I work in healthcare software, I want it to be right, because I don't want my fuck-ups to kill a patient. But even if I didn't, I'd still prefer to write code this way because it is sooo much easier to manage the mental model of the code-base, especially when the code-base is super-large.

> but not enough that the whole house needs to be rebuild if a little requirement detail changes

That isn't my experience at all. If the whole house needs a rebuild when some little requirement detail changes then you're doing it wrong, sorry. One thing that can happen when using sum-types instead of inheritance, is that adding a new case to the sum-type requires you to go and consider all pattern-matching usages of it. This can be painful, but it forces you to consider the impact of your change. I believe this to be a good thing and compilers usually help you here anyway. This trade-off is captured in the Expression Problem [2]

[1] https://news.ycombinator.com/item?id=34847326

[2] https://en.wikipedia.org/wiki/Expression_problem

Re: John Carmack on Functional Programming in C++ (2018)

#102
post #62

Earlier quoted context omitted.

I would say it's often the opposite, unless I'm misunderstanding you. Instead of being encapsulated "deeply" in a class ancestor, state in FP is in the "top" of the program, in the "shallow" part, as explicit as possible and as close to the entry point as possible, while the functional part is the thing that is in the middle. The term for this is "Functional core, imperative shell". In something like Haskell, side-ef…

Um... ok. I think we're sort of both talking about keeping logic unbound from artifacts like display and from objects that contain state. Where I think OO makes sense is that once you admit that objects have properties it makes sense to take the top form of that object and put the functionality there - rather than abstracting it away into some completely other logical place. Maybe this all comes down to what I find e…

I think you’d love FP if you gave it a real, honest chance.

Re: John Carmack on Functional Programming in C++ (2018)

#103
It has helped me see classes as a group of functions with parameters in common. The constructor helps me reduce the amount of params passed to each function. If I avoid mutating the internal state across function calls, I'm just using them as a way to group functions together (as a module would).

Instantiating and then calling different methods helps me test a process at different points of the executing (testing and debugging). Inheritance helps me clean up stuff that's repeated in specific sub-problems. Mixins/modules help me in a similar way, but for stuff that's reusable in unrelated problems.

I'm writing this with Ruby in mind. Seeing how OOP constructs can help me manage code that's written in a functional style has given me a middle ground: I started as 'FP is superior; use everywhere; avoid OOP languages' and now see the OOP stuff just as tools that can make it easier for me to encapsulate and reuse logic. Obv this comes with footguns: taking outside params in methods, local variables changing behaviours, indirection from inheritance/extension - the list goes on and other languages have their own. There's problems with it but as the author says, these things aren't all-or-nothing - so you can nudge the codebase in the FP/'pure' direction.

"Objects are a poor man's closure.... Closures are a poor man's object."

Re: John Carmack on Functional Programming in C++ (2018)

#104
post #61

> A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in. I think this probably the most important concept for programmers to keep at the front of their minds when working day to day. So many of the problems I see come from developers (myself included) adding new business logic to a process, or fixing a bug and not thinkin…

> adding new business logic to a process, Adding logic is the smallest part of the problem: adding types, that aren't constrained to represent the smallest set of values needed for the problem at hand, that's the biggest problem. This 'looseness' doesn't show up as a compilation error and looks on the surface to be just fine. Then the real-world comes along and creates a value that should never exist and the code fal…

Games and many similar domains are harder to write code for than CRUD. What you talk about works well for CRUD apps, but basically every set of development ideas works well for CRUD apps, it isn't hard to do.

Re: John Carmack on Functional Programming in C++ (2018)

#105
post #61

Earlier quoted context omitted.

> adding new business logic to a process, Adding logic is the smallest part of the problem: adding types, that aren't constrained to represent the smallest set of values needed for the problem at hand, that's the biggest problem. This 'looseness' doesn't show up as a compilation error and looks on the surface to be just fine. Then the real-world comes along and creates a value that should never exist and the code fal…

Games and many similar domains are harder to write code for than CRUD. What you talk about works well for CRUD apps, but basically every set of development ideas works well for CRUD apps, it isn't hard to do.

As an ex-3D engine dev, I respectfully disagree. But if you're happy to give some examples of why you can't constrain your data-types then I'm happy to admit I'm wrong.

I realise sometimes there's aspects of a game that needs to write to the metal, and compromises need to be made, but that isn't necessary for an entire game. I know people are using my language-ext library with Unity projects too, so I assume there are others in games that don't agree (although I don't know exactly what kind of titles they're working on).

[1] https://github.com/louthy/language-ext

Re: John Carmack on Functional Programming in C++ (2018)

#106
post #105

Earlier quoted context omitted.

Games and many similar domains are harder to write code for than CRUD. What you talk about works well for CRUD apps, but basically every set of development ideas works well for CRUD apps, it isn't hard to do.

As an ex-3D engine dev, I respectfully disagree. But if you're happy to give some examples of why you can't constrain your data-types then I'm happy to admit I'm wrong. I realise sometimes there's aspects of a game that needs to write to the metal , and compromises need to be made, but that isn't necessary for an entire game. I know people are using my language-ext library with Unity projects too, so I assume there a…

3d engine is very structured, it isn't the creative part of game development.

Lets say you want to test your bullets having HP and can be shot down. So you add that in an hour, now bullets have HP, you test it, it doesn't work, so you remove it. Things like that needs to be seamless, because you need to iterate on ideas and test if things are fun. Big upfront design as you suggest where you very carefully constrain everything doesn't do well with that. It works well for 3d engines for example sure, but 3d engines are much more constrained than games.

Re: John Carmack on Functional Programming in C++ (2018)

#107
post #2

This guy really really knows how to explain things succinctly and expressively.

I was impressed by his concise daily planfiles. https://github.com/ESWAT/john-carmack-plan-archive/tree/mast...

thanks for sharing, do you know what those three sections (*, + and empty) mean?

Re: John Carmack on Functional Programming in C++ (2018)

#108
post #35

Earlier quoted context omitted.

i am by no means a java expert, but i would have thought that the fact that most objects in java are shipped between functions as references makes purity more difficult to effect and to diagnose than in c++ where everything is by default shipped as a value - of course c++ allows you to change this , java less so?

While you're not wrong RE: object references, Java does have the `final` keyword that you can apply to fields, local variables, method arguments, etc. This prevents the value from being re-assigned short of going out of your way to do reflection hacks and such. You can also apply it to classes themselves and prevent them from being inherited and modified that way. The only real 'gotcha' there is that, while it preven…

At that point, why not just use Scala? Get all the immutability, implicits, etc without bolting these things on? I’m asking more rhetorically and there are organizational constraints from doing so, but it seems like if you’re looking for more FP, better solutions still exist on the JVM.

Re: John Carmack on Functional Programming in C++ (2018)

#109
post #105

Earlier quoted context omitted.

As an ex-3D engine dev, I respectfully disagree. But if you're happy to give some examples of why you can't constrain your data-types then I'm happy to admit I'm wrong. I realise sometimes there's aspects of a game that needs to write to the metal , and compromises need to be made, but that isn't necessary for an entire game. I know people are using my language-ext library with Unity projects too, so I assume there a…

3d engine is very structured, it isn't the creative part of game development. Lets say you want to test your bullets having HP and can be shot down. So you add that in an hour, now bullets have HP, you test it, it doesn't work, so you remove it. Things like that needs to be seamless, because you need to iterate on ideas and test if things are fun. Big upfront design as you suggest where you very carefully constrain e…

> 3d engine is very structured, it isn't the creative part of game development.

I also did lots of the creative bit ;). I just assumed this was going to go down a performance route question, sorry!

> Big upfront design as you suggest

No, I am not suggesting that at all - I'm saying the opposite of that. You're the third person to think that's what I am saying now, so I assume I didn't explain myself very well. Rather than repeat myself again, my other replies cover this [1] [2]:

[1] https://news.ycombinator.com/item?id=34847413

[2] https://news.ycombinator.com/item?id=34847326

Re: John Carmack on Functional Programming in C++ (2018)

#110

As a 25+ years coder who's very accustomed to thinking in my own ways, I have a problem with functional-purism similar to the problem I had with globals and factory functions. The fact is that most programs have a lot of states and these states have to be represented somehow. Allowing the objects to contain functions that act on those states is a perfectly good analogy for most business logic or game logic you're mod…

> these states have to be represented somehow In data types! > But so many functions are more comprehensible when they take place bound to the scope of what it is they're acting upon To me, the most understandable function (lowest context needed, lowest cognitive overhead) is a black box that takes type x as input and produces type y as output, without side-effects > I don't think that thinking in terms of objects or…

> To me, the most understandable function (lowest context needed, lowest cognitive overhead) is a black box that takes type x as input and produces type y as output, without side-effects

True, however we must be careful not to go completely bananas either; it's really hard for a reader to piece back together a full mental picture if the functionality is spread into dozens even hundreds of general-purpose 3-line functions.

Simple, `y = f(x)` types of functions are indeed the easiest to understand, but you might be no closer to understanding what the code is actually doing.

Post reply on HN