My irrational fear of Python

Started by
26 comments, last by MDI 16 years, 11 months ago
Quote:Original post by hymerman
Niktheblak: I'm investigating it now. I figured functional programming may be able to help me, I just don't know if my mind is ready for it yet! How on earth do I draw to the screen in a functional language...?

The following code draws a star on the screen in Haskell, using OpenGL. Taken from here.
ex2 :: IO ()ex2 = do  color (Color3 0.0 1.0 0.0 :: Color3 GLfloat)  beginEnd LineLoop $ mapM_ vertex [		Vertex3 0.20 0.10 0.0,		Vertex3 0.50 0.90 0.0,		Vertex3 0.80 0.10 0.0,		Vertex3 0.10 0.60 0.0,		Vertex3 0.90 0.60 (0.0 :: GLfloat)]

In Haskell you basically have a datatype, IO, which represents an "action" - writing to a file, or drawing on the screen. This datatype also happens to be a "monad". A monad is basically a datatype which implements the Monad interface (type class) and obeys a few rules - there are many more useful monads that have nothing to do with IO. The 'do' syntax seen above looks imperative, but is transformed into code using this functional interface.

This setup allows the language to keep referential transparency, while still interacting with the outside world. The code responsible for building actions is kept as localised as possible, so you have a few top-level functions responsible for effects calling out into effect-free code which does most of the work.

I highly recommend picking up Haskell. As a bonus, you'll see how static typing done correctly really is a feature.
Advertisement
Okay, cool. So I see how to draw lines and polygons now, but how's about all the super advanced stuff like meshes, textures, shaders, bones, VBOs, scene graphs and so on? Looks to my puny brain like this kind of code would quickly get very messy and tangled in a functional language, or at best produce something very terse and hard to follow. Are there any examples of, say, proper game/rendering engines written in Haskell?

Or... would all that complex stuff be done in some C++/whatever library, which would have Haskell bindings?
Quote:Original post by hymerman
Quote:Original post by mikeman
... In C++, it happens a little more often, because of things like "char*" vs "const char*" and the like, things that don't matter in Python.


Well, I kind of want them to matter. How else would I promise to users that a method won't mutate their data?


You put a comment above the function saying "does not modify the data".

Either the 'user' (which is usually you) can trust you, or they can't. 'const' means very little when you can just cast it away in your function anyway, or edit a mutable data member, or make a void pointer from it and start jabbing random bytes over the top. Const makes no promises to the caller of the function that the caller can guarantee will be kept. It just places a restriction on the writer of the function and adds compiler checks to ensure that you're doing what you intend to do. It's not without merit - C++ is better for having this than it would be without it - but the benefits are small.

Quote:Kylotan: Point 1 goes a long way to convincing me, I don't like anything existing for legacy reasons... but still, the same doubt is there; how do I guarantee my methods won't explode when provided with incorrect types? Or rather, why shouldn't I worry about this?


99% of the time that C++ complains that I pass the wrong type to a function, it's for one of these reasons:

- It's a typo and I'm passing the wrong object entirely (almost all the time this will end up causing an obvious exception at run time in Python when the called function tries to access members or operations that don't exist on the object)

- I've forgotten to declare something as const, so it worries that I might be modifying the object, even I'm not actually doing so (not an issue in Python because you don't have const in the first place)

- C legacy code requires char* whereas much of my code requires std::string (not a problem in a language with strings as a first-class type)

- I've not overloaded the << operator (but languages like Python don't require that for you to print out an object or send it to a stream)

Can you think of others?
Quote:Original post by hymerman
Okay, cool. So I see how to draw lines and polygons now, but how's about all the super advanced stuff like meshes, textures, shaders, bones, VBOs, scene graphs and so on? Looks to my puny brain like this kind of code would quickly get very messy and tangled in a functional language, or at best produce something very terse and hard to follow.
I don't see why. Tim Sweeney of Epic Games comments in The Next Mainstream Programming Language: A Game Developer's Perspective that scene graph traversal, physics, collision detection, path finding and sound are all "essentially functional".

He states elsewhere that 70% of the code Epic writes, which accounts for 95% of their performance profile, could be written in a purely-functional style. The other 30% of code that accounts for 5% of their performance - interactions between game characters and the like - probably requires the use of state.
Quote:
Are there any examples of, say, proper game/rendering engines written in Haskell?

Frag is a 3D first person shooting game written in Haskell.
Quote:Original post by Kylotan
You put a comment above the function saying "does not modify the data".


Argh! I was waiting for someone to say that! I've recently gone off the idea of comments altogether, having seen that they end up almost entirely irrelevant when using TDD. I really don't like commenting on the semantics, since comments essentially mean nothing.

Quote:'const' means very little when you can just cast it away in your function anyway, or edit a mutable data member, or make a void pointer from it and start jabbing random bytes over the top. Const makes no promises to the caller of the function that the caller can guarantee will be kept.


Fair enough, C++ annoys me in this respect too. I'd much prefer it if const meant what it said.

Quote:99% of the time that C++ complains that I pass the wrong type to a function, it's for one of these reasons:

...


Also fair enough. So you're saying that although it's lovely to be able to make all these guarantees about correctness and whatnot, they're not really needed, or even practical? I must agree that in general it just ends up being an annoyance due to poor error messages and type inference, but isn't that just down to C++ itself being a bit of a mess, and compilers having a hard job to do? If the compiler could tell you genuinely useful things about what you're doing wrong, wouldn't that be useful? For example, what if it could tell you at compile time what exceptions you haven't accounted for and may be unhandled?
Quote:Original post by Oluseyi

Quote:Likewise I don't enjoy having to wait until a particular line of code has been executed to tell me that I got the order of parameters the wrong way around.

Ever heard of unit testing?
So you just have to test every single line of your code during development, plus you have to add code that checks the correctess of every single parameter in every single function, and you wouldn't need static typing?
Well, yes, of course you wouldn't, because you're actually implementing it (and calling the compile phase "unit tests").
_______________The essence of balance is detachment. To embrace a cause, to grow fond or spiteful, is to lose one''s balance after which, no action can be trusted. Our burden is not for the dependent of spirit. - Mayar, Third Keeper
Python can be great for tool development and prototyping. You don't need to be so strict with unit tests in this case because no one in the outside world will actually be using these things. Not having to make type information explicit can make the code a lot cleaner and make it easy to implement dramatic design changes that would require going back and fixing a lot of code in a more static language.

The code tends to be cleaner so it is also easier to read it and verify that the program is doing the right thing.
Quote: Original post by Kylotan:
1) Static typing and type safety can be viewed as retroactive excuses made for the rigidity of the language. For efficiency reasons it's necessary to know the size and layout of a type at compile time so that the correct offsets can be used to access members, etc. Then you can brand this a 'feature' and call it 'safety'. I can count on my fingers how often I've compiled code that tried to pass the wrong type to a function and was grateful for the safety, in 20 years of programming. And unlike in C++, if you did that in Python and passed the wrong type in, you almost always get a clear and unambiguous exception raised as soon as you try and use that object in the wrong way, rather than memory being invisibly trashed or the like.


I think you're conflating a lot of different arguments, here. There's a critique of C++'s type system masquerading as a critique of static type checking. Any number of programming languages have been explicitly designed with static type checking in mind, not simply as a "retroactive excuse for language rigidity" (the ML's, Haskell, etc.).

This topic is closed to new replies.

Advertisement