12 ms·
John Carmack starting port of Wolf 3D in Haskell
- wting 13y agoCarmack has been thinking about functional programming for a while and posted his thoughts on applicable lessons for C++ a year ago: http://www.altdevblogaday.com/2012/04/26/functional-programming-in-c/ http://www.altdevblogaday.com/2012/04/26/functional-programm... He's a great developer and has always pushed boundaries. I look forward to his postmortem after this project is finished.
- keyle 13y agoOne of his best posts imho. Worth reading and reading again for any Object Oriented developers.
- jfb 13y ago"Large scale software development is unfortunately statistical." Too true.
- blt 13y agoMaybe if all of the objects just referenced a read only version of the world state, and we copied over the updated version at the end of the frame… Hey, wait a minute... This sounds like a game development reference that I'm missing. Can anyone explain?
- AaronFriel 13y agoHe's alluding to frame buffers.
- blt 13y agoDo a lot of other objects read the "front" frame buffer besides the video output?
- obviouslygreen 13y agoI think the whole point of a "front" framebuffer is that its only purpose is to be written to the screen. You're only ever writing to the back buffer, which is then flipped, at which point you're writing to a new buffer and it's the next frame. [edit: If I'm wrong... ouch. But it's been a while.]
- blt 13y ago@obviouslygreen that is why "all of the objects just referenced a read only version of the world state" doesn't make sense to me as a frame buffer analogy...
- xsmasher 13y agoIt sounds like he's talking about double-buffering "model" data - like an array of all actors and their positions. You can't have one thread reading the data while another writes to it, but you can have the reading thread work on an "old" copy of the data while the writing thread modifies the live data. Games often want physics/model threads run with a consistent timestep, but have the rendering thread run as fast as possible.
- chipsy 13y agoHe's referring to the utility of immutable data for solving certain parallelism issues - rather than attempt to coordinate all the code that uses a data structure, you can double-buffer it and queue up the write events for the "next frame" instance. This is a hugely successful pattern throughout a number of aspects of gaming, graphics being one of the most classic examples. Double-buffered graphics don't suffer as much from tearing and other display artifacts.
- laureny 13y ago> This is a hugely successful pattern throughout a number of aspects of gaming, graphics being one of the most classic examples. Not really, no. Immutability comes at the cost of performance compared to mutability. The gap is shrinking between the two, but it's still wide enough that using pure immutable structures for frame buffers, shaders and other graphical concepts is simply not an option to write games. Haskell is interesting in the sense that it doesn't prevent you from using mutable structures (e.g. Lenses, Writer) but it encodes this information in the type system. I'm really curious to read the conclusions that Carmack will draw from his experience but I wouldn't be surprised to read that at the very low levels, mutable structures are just unavoidable for high performance games. Also, mutable structures accessed by concurrent threads is a problem that's much less difficult than most people claim, and it's often much easier to reason about locks and semaphores than about immutable lazily initialized structures.
- DanWaterworth 13y agoI don't know where to start. > using pure immutable structures for frame buffers, shaders and other graphical concepts is simply not an option to write games. Seeing as people have written games in Haskell, this is clearly not true. > Haskell is interesting in the sense that it doesn't prevent you from using mutable structures (e.g. Lenses, Writer) Lenses and Writer both only use immutable data. It is possible to use actual mutable data in the ST and IO monads. > but it encodes this information in the type system. This is true of IO, but not of ST. With ST, runST :: (forall s. ST s a) -> a, hides the effects. > it's often much easier to reason about locks and semaphores than about immutable lazily initialized structures. I don't know what you mean by this. In terms of functional correctness, immutable data-strucutures, lazy or otherwise, are much easier to reason about. If you are talking about resource-usage, sure, it's a little harder to reason about lazy data-structures than strict ones, but give me a space leak over a race condition to track down any day.
- jjs 13y agoModern OpenGL exploits immutable data for parallelism all over the place. It also lets (and expects!) you to upload model data (vertices, colors, texture-coords, etc) to the GPU, so you only need to re-upload things that have changed. You can even stream textures asynchronously using PBOs (pixel buffer objects), and use dual PBOs like double buffers (or using copy-on-write techniques to only re-upload dirty rectangles...)
- signa11 13y agothanks for the excellent link. the comments on the article are also very nice. here is one from "NathanM" (nathan-c-meyers perhaps ?): And yes, I'd love it if the compiler (or other static code analysis) could detect how pure various bits of code are, and give reports. For far too long, compiler authors have treated compilers as a big opaque box that end users (developers) submit code to, and the compiler hands out code as if from on high. Smart developers want to have a 2-way communication with their compiler, learning about all sorts of things -- functional purity, headers over-included, which functions it decided to inline or not (especially in LTCG), etc. It's not the 1960s anymore -- developers aren't bringing shoeboxes of punchcards of source code to submit for offline processing. Let's get closer to a coffee shop where we can talk in realtime.
- tikhonj 13y agoI think things are trending towards being more interactive. In the immediate future, GHC is going to become more interactive by adding "type holes". Essentially, you can just leave out parts of your program and the compiler will tell you what type needs to go there. So instead of writing your program and checking if it typechecks, the type system can actually help you formulate the code in the first place! Further afield, a bunch of people at the lab I'm working at are working on interactive systems that use a solver running in the background to solve problems for the programmers. These can be used to do all sorts of things from finding bugs to actually generating new code. Being interactive lets the solver suggest things without being 100% certain--the programmer can always supply more information. This also makes the solvers easier to scale because if it's not terminating quickly, it can just ask for more guidance from the programmer. I think the general trend towards more interactive development is pretty exciting.
- kwantam 13y agoThere's already a very primitive version of "type holes" available, namely, undefined. I realize it's not as advanced as what's to come, but I find myself using it somewhat frequently. (For non- or fledgling Haskellers, "undefined" has any type, so if you define a function that plugs into your code and make its return value "undefined", then you can look at the type signature of the function and learn what the compiler proved about the type of that function. Pretty handy!)
- shurcooL 13y agoI'm a big big supporter of this. I had one thought [1] I wanted to add to the excellent linked article. I'm not sure if my thought is obvious or insightful, but I like it. I try to write all my new general/reusable code as pure functions whenever possible (which is almost always). [1] https://twitter.com/shurcooL/status/327249579189870592 https://twitter.com/shurcooL/status/327249579189870592
- b0rsuk 13y agoThen I guess I was just ignorant. For me he was always one of the C icons and diehards, similar to Linus Torvalds. He's incredibly conservative about games and doesn't value creative game mechanics. But it's nice to hear, hopefully John Carmack and id will make at least one more great in the future.
- pjmlp 13y agoC icons? His games have been C++ for quite some time now.
- b0rsuk 13y agoI meant C as in "C family of languages". C++ is still closer to C than to Java. I admit mentioning him alongside Linus was misleading. Haskell is a paradigm shift.
- papsosouid 13y ago>I admit mentioning him alongside Linus was misleading And quite insulting.
- Altenuvian 13y agoto whom?
- papsosouid 13y agoMr. Carmack. Linus is famous, but not a particularly good programmer, and doesn't use C over C++ for technical reasons, but for "ability to offend people" reasons.
- zura 13y agoTo be honest, it was more "C with classes" style of C++.
- dietrichepp 13y ago
- antonios 13y agoWhose postmortem, the project's or Carmack's? With Haskell, you never know...
- marshray 13y agoHey Haskell never killed anyone that we know of. That would be an observed mutation of state. However, it may be (if you'll pardon the expression) garbage collecting people that we don't know about, or cloning them in such a way that their multiple representations are indistinguishable.
- ctdonath 13y agoAny word on a Quake port to iOS?
- thezilch 13y agoI also had to make one last minute hack change to the original media -- the Red Cross organization had asserted their trademark rights over red crosses (sigh) some time after we released the original Wolfenstein 3D game, and all new game releases must not use red crosses on white backgrounds as health symbols. One single, solitary sprite graphic got modified for this release. I always wondered about color choices for some games' health packs.
- octo_t 13y agoAs much as thats annoying, it does make a lot of sense. If you can assert that everything which bears that logo is going to be medically related (and not just something random), especially in wars and the like, means you can be more certain of someones intentions.
- ricardobeat 13y agoEspecially presence/touch-activated explosive devices.
- marshray 13y agoWars observe trademarks? I thought the Red Cross was established by international treaty. https://en.wikipedia.org/wiki/First_Geneva_Convention https://en.wikipedia.org/wiki/First_Geneva_Convention
- dllthomas 13y agoNo, but if there is a red cross on white on a sign, it's good to know it's not just advertising from back before the region became a warzone.
- mzs 13y agoHow long before? http://upload.wikimedia.org/wikipedia/commons/0/0d/Knights_Templar_Cross.svg http://upload.wikimedia.org/wikipedia/commons/0/0d/Knights_T...
- ineedtosleep 13y agoWhat would be the immediate benefits of this? Would it be mostly related to multithreading? And on a side note: As a NoScript user, I'm surprised that I've had to give Javascript permissions to Twitter just so I can visit that idsoftware.com link inside of the tweet. Obviously I don't visit Twitter often, but that should never be the case for it or any site.
- dllthomas 13y agoImmediate benefits of porting an ancient game that runs fine on just about anything? It's not about the result, but the process of building it. Lessons learned can be applied to situations where the result does matter (and, hopefully, blogged about).
- sultezdukes 13y agoI recall Carmack used to go on week-long Sabbaticals, where he would lug his computer to a hotel room and do research. It's probably along those lines, though I doubt his wife and kid(s) would allow him to do that these days ;)
- dubcanada 13y agoIt's fun... He's a developer who enjoys doing stuff, it doesn't matter if it has a purpose. To him it does, and he has enough followers that he felt he should share it with people, which makes sense considering I can't wait to see the result. And I'm sorry, but if you turn off javascript this day and age you should expect more sites to not work then to work. You're turning off part of the browser, and you do not like having to turn it on to use the browser? Seems a little backwards to me... considering the extremely small population of noscript users. I also understand that I'll probably get down voted into oblivion as every single noscript users is probably on this site. But it's true...
- RexRollman 13y agoI think he was just surprised that something like a simple link needed Javascript.
- 13y ago
- taeric 13y agoI'm more than a little curious at what folks are thinking this will prove. I mean, to a large extent this feels like it would be akin to watching a master photographer switch from film to digital. The vast majority of the craft is hard to see at the implementation layer. I mean, consider everyone's favorite sort method. Seeing it implemented in any language does little really show how amazing the original insight was. I rush to say that I am highly interested in seeing this. Nor do I question what Carmack is looking to see. It is strictly the talking heads around this that have me somewhat... off.
- pyre 13y agoPersonally, it's just interesting to see the original creator start such a port. Especially when the original creator is of the calibur that Carmark is.
- taeric 13y agoOh, no doubt. I guess I'm just prejudiced by seeing "case stories" held up as some sort of "see, this person was able to do it, language/technique/tool/whatever X is ready for everyone to use! And will solve all problems!" So, yeah, I'm projecting. No, I don't know why. :( Sorry.
- sillysaurus 13y agoIt's healthy to be skeptical. But it's unhealthier not to try everything and discover what works. It's pretty rare for someone to immediately see which of several possible new inventions might be better (and why they're better). I'm referring to the inventor -- an inventor often has several possibilities for new things he could try to do, and he has to choose which of those to pursue. It's not at all obvious which path to choose. So most of the time, you just try all possibilities as fast as possible, letting intuition guide you. For example, it probably wasn't immediately obvious to DHH that it was a win to write websites in Ruby until he'd tried writing websites in Ruby to see how it'd turn out. History tends to get rewritten so that it's obvious in hindsight that it would work. But it wasn't at all obvious until it was suddenly obvious to him, which was only after he'd had the experience of trying it. So the interesting aspect here is that Carmack's intuition has told him that there might be something worthwhile for the videogame industry to look into functional programming languages. It probably won't pan out. But if there's any way it can, then Carmack will find out how to make it a pragmatic way for studios to build large codebases.
- the1 13y agoit's gonna be another perl 6.
- pjscott 13y agoJohn Carmack is actually pretty good at writing Wolfenstein 3D.
- pistacchioso 13y agohttp://en.wikipedia.org/wiki/John_D._Carmack http://en.wikipedia.org/wiki/John_D._Carmack
- audreyt 13y agoTBH, this seems more like porting perl 1 ( https://github.com/TPF-Community-Advocacy/perl1.0 https://github.com/TPF-Community-Advocacy/perl1.0 ) to Haskell. :-)
- deleted 13y ago[deleted]
- Legion 13y agoHis post about the iOS port of Wolf3D was a great read, and also a crystal clear reminder of why I never play 3D games on a touchscreen-only device. The means of input are so truly terrible that I do not understand why anyone bothers. But, clearly, there's an audience that does not care, and it was neat to read about all the things Carmack tried to figure out how best to pull it off.
- adventureloop 13y agoYou should try Galaxy on Fire 2. The trend seems to be towards difficult 3D controls, but you cannot write off the entirety of 3D games because you haven't seen good samples.
- sunwooz 13y agoCan someone tell me what exactly a 'port' is? Is it just rewriting all the code base in a target language?
- brooksbp 13y agoRewriting the code base in another language would be considered a 'rewrite'. Usually, ports are in the same language but targeted at a different platform whether that be an OS or architecture, or even something like a different graphics library (OpenGL game ported to DirectX).
- vidarh 13y agoReferring to total rewrites in different languages as "ports" has a history in the game development world going back to the beginning, when those doing "ports" often did not even get access to original source or assets, and the games would be written in asm for the target platform anyway.
- tellarin 13y agoPorting is to make something that runs in a platform/environment run in another one. Not necessarily having to do with coding in another language. Sometimes it's just a recompilation, or providing a new hardware abstraction layer (HAL). But sometimes it can lead to major re-development of the whole thing, be it using the same language, or a different one.
- kleiba 13y agoHere's a question for my fellow HNers. In the article linked from his tweet, Carmack describes how he ported Wolfenstein3D to the iPhone. He apparently didn't start off with their own original code base, but used the open source project "Wolf3D Redux" (http://wolf3dredux.sourceforge.net http://wolf3dredux.sourceforge.net) as a starting point. This was possible because id open sourced their original game, and "Wolf3D Redux" is distributed under the GNU GPL v2. Carmack also states: "I think the App Store is an extremely important model for the software business." Therefore my question: is it possible to publish GPL'd games in the App Store? I seem to remember that this was not possible, since ToS of the app store impose further constraints which is forbidden under the terms of the GPL.
- mhaymo 13y agoI think it's only GPLv3 which forbids distribution on locked-down devices. I would guess that GPLv2 is compatible with the iPhone.
- nglevin 13y agoIt's possible, though it depends on the wishes of the original authors. Stockfish Chess [1] is the one GPL v3 licensed app that I know of which has been available for... quite some time, now. I've seen several other Chess apps build on that engine, which go as far back as when I was just starting iOS development. Now, VLC was the one case where one volunteer for the project invoked the GPL to get Apple to take an iOS port of the app off the store [2]. Based on that situation, it seems that if the original authors of a GPL licensed codebase want to pursue a claim against an app that uses that code, they can, and Apple will take it seriously. I don't believe that situation has changed. EDIT: For your own sake, it's probably best if you approach the original author to see if they can make an exemption, in writing, for the DRM situation. IANAL, but that seems like it would be the cleanest way to go about handling GPL licensed code without issue. [1] - http://stockfishchess.org http://stockfishchess.org [2] - http://www.tuaw.com/2011/01/08/vlc-app-removed-from-app-store/ http://www.tuaw.com/2011/01/08/vlc-app-removed-from-app-stor...
- rmc 13y agoRemember, you'll need to contact all the authors and they all have to consent to (essentially) relicense their code. Any open source project that accepts patches may have dozens of actual authors. You can't just ask the project maintainer/chief contributor.
- b0rsuk 13y agoA bit off-topic: has John Carmack made any comments on Go programming language ? It sounds like a language that should appeal to him. The name makes it not easy to google for (I've tried golang, etc). I couldn't find anything, is it because Go has a far way to go before it's mature enough to use in games ?
- zackzackzack 13y agoProbably because there are like a billion other things he has to do.
- humanrebar 13y agoConsidering the language features that Carmack is interested in, Rust seems like a better candidate than Go for him. Unfortunately, Rust isn't even in beta yet, so it will be a while before it's suitable for anything except experimental projects. The D language has a lot of features that should appeal to large software projects, including a certain amount of feature overlap with the functional languages. It hasn't really taken off yet, but it could be a killer app or two away from taking off. Maybe. I say all that to say that Go seems fantastic for server-side programs but I suspect other prospective languages will be better for large, performance-critical games, but I've been wrong before.
- Tuna-Fish 13y agoAs of right now, Go is essentially completely uninteresting to game dev because it's not possible to guarantee steady frame rates in it. (The GC solution is bad for latency.) Also, I doubt Carmack would be interested in Go -- based on his previous talks, he seems to be going for a more functional approach. Go is imperative to the bone.
- gillianseed 13y agoWell I would agree if we are talking about very demanding current gen style games (which id software indeed typically produce) but if we look at indie-style games then having garbage collection doesn't preclude a language from being used in games development, or having steady frame rates. There's no technical reason I can think of why Go wouldn't work just as well as C# (XNA/XBLA/MonoTouch/Android) or Java (Minecraft etc) for game development. Garbage Collector sweeps can indeed be a performance problem but there are obvious ways of minimizing it's impact during gameplay. Overall I think (read guess) that unless you are doing some sort of physics simulation, typical game logic requires relatively little cpu power and for the graphics there is hardware acceleration doing the heavy lifting.
- Arjuna 13y agoIn case you were not aware, the iOS source code for Wolfenstein 3D Classic Platinum is licensed under GPL. It is available here: http://download.zenimax.com/idsoftware/src/wolf3d_ios_v21_src.zip http://download.zenimax.com/idsoftware/src/wolf3d_ios_v21_sr... I thought this story was cool: "[...] They were using the software rasterizer on the iPhone. I patted myself on the back a bit for the fact that the combination of my updated mobile renderer, the intelligent level design / restricted movement, and the hi-res artwork made the software renderer almost visually indistinguishable from a hardware renderer, but I was very unhappy about the implementation. I told EA that we were NOT going to ship that as the first Id Software product on the iPhone. Using the iPhone's hardware 3D acceleration was a requirement, and it should be easy -- when I did the second generation mobile renderer (written originally in java) it was layered on top of a class I named TinyGL that did the transform / clip / rasterize operations fairly close to OpenGL semantics, but in fixed point and with both horizontal and vertical rasterization options for perspective correction. The developers came back and said it would take two months and exceed their budget. Rather than having a big confrontation over the issue, I told them to just send the project to me and I would do it myself. Cass Everitt had been doing some personal work on the iPhone, so he helped me get everything set up for local iPhone development here, which is a lot more tortuous than you would expect from an Apple product. As usual, my off the cuff estimate of "Two days!" was optimistic, but I did get it done in four, and the game is definitely more pleasant at 8x the frame rate. And I had fun doing it." [1] [1] http://www.idsoftware.com/iphone-games/wolfenstein-3d-classic-platinum/wolfdevelopment.htm http://www.idsoftware.com/iphone-games/wolfenstein-3d-classi...
- Aardwolf 13y agoSo how do you keep state like health points in a functional language? :)
- cobrausn 13y agoFrom what I hear (I don't use functional languages, so I don't know for sure), functional languages minimize state, but don't erase it entirely.
- MatthewPhillips 13y agoHealth points isn't a state, it's a piece of data that exists at a given time. If you have time, go on YouTube and watch some talks Rich Hickey gives about state, he breaks it down far more eloquently than I can.
- papsosouid 13y agohttp://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad-State-Lazy.html http://hackage.haskell.org/packages/archive/mtl/latest/doc/h...
- ufo 13y agoOne way you could do it is by using mutable state. Impure languages, such as Scheme or Ocaml, let you use mutable like normal imperative languages do and in Haskell you can use mutable references inside some special monads (and you even ave more than one kind of mutalbe reference, depending on what monad you are on: IORef, STRef, etc) The other way is to not use state. If you squint a bit, you can see that if you explicitly encode your "state" as function arguments you can kind of update it by calling the function recursively: go 0 acc = acc go n acc = go (n-1) (n * acc) fact n = go n 1 In the previous example, the code I wrote does exactly the same thing as the usual imperative loop might have done, but the accumulator is a parameter on the helper function instead of being a mutable variable. In general, if you are OK with this kind of non-destructive updates that I used here, you can encode all your state as extra parameters that you thread around your functions. You can do this by hand in most cases but in some situations the state is very pervasive and correctly threading it around can be complex and error prone. In that case, you can look into use things like the State monad (not to be confused with the ST monad!) to do that implicitly pass that parameter around for you.
- GrandTheftR 13y agoThis is encouraging, have been working on my game in Haskell for last few weeks, it is fun. Hope to see more insight & progress from John soon.
- bwooceli 13y agoMy heart goes out to the poor Redux project maintainer. Can just imagine him a few months from now checking on his old email address that he's forgotten about and finding John's invite. Friendly reminder to everyone to keep your project contact info current.