Sometimes I have to implement a feature like customized drag & drop. The code may goes like this:
bool mouse_down = false;
Vec2 mouse_pos;
void on_mouse_down() {
mouse_down = true;
mouse_pos = cursor_pos();
}
void on_mouse_move() {
if(mouse_down) {
Vec2f c = cursor_pos();
Vec2f d = c - mouse_pos;
// dragging. make objects tracing the cursor.
// ...
}
}
void on_mouse_up() {
mouse_down = false;
// dropped
// ...
}
I know this works fine, but I donnot like redundant variables and separated procedures for something like this at all. In IP(imperative programming) maybe it's unavoidable; my question is, is there a better way to deal with this kinda thing in FP(functional programming)? Any ideas and suggestions are appreciated, no matter whatever programming languages, Lisp, Scheme, F#, Ruby, etc. or some better way to do this in IP?
Since nobody attempted an answer for a day, I'll give it a shot. I understand the problem that you are discussing, but the answer should likely depend on the operating system, language and its runtime library.
The general idea would be that when mouse goes down, you spawn off an asynchronous computation. This computation "blocks" on events, and processes them in its own loop as fetched, doing what you need to do; it exists when the mouse button does up. While this looks like it works like an imperative thread, in reality, when the computation gets "blocked", it just yields control to where it was started from (the main GUI thread invoking the mouse down event, presumably). In such a way, the state is encapsulated into what looks like a lexically local scope of the computation. That magic has to be handled by the runtime of the language, so this is as far as we can get with the answer in a language ans OS-agnostic way.
As for an example of such implementation, check this answer and an article by Tomas Petricek, both discussing your question but in a narrow setting of Windows, .NET and F#. There is a book by the same Perticek, Real World Functional Programming: With Examples in F# and C#, where the same ideas are expressed, surprisingly, in C#, not usually regarded a functional language. Chapter 16, if my memory serves me, is yours.
As for encapsulating the state in an IP/OO language program, you can create an instance of a class in your mouse_down handler. The instance would register itself with the runtime to receive other mouse and UI events, process them, do all the work and, when needed (mouse goes up or the windowing system cancels capture mode), unregisters and destroy itself. Not as elegant as a functional language would allow, but still much better that keeping mutable state in a general UI class.
Related
This is one of the things that still confuses me about QML / QtQuick: How shall I implement a simple game like pong that uses a loop?
I googled a bit and looked through similar questions here but none of them addressed the following:
I want to create a simple game like pong that uses a loop. In this loop first all the objects are updated (in case of pong the ball and the bars) and then everything is rendered. For the rendering part I think QML will do the job once all the properties are set.
I want to use QML and QtQick and not QGraphicsScene.
I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.
Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.
I had a similar question when I first started with Qt and got the same answers you're getting (which are correct). It's a different way of thinking than if you had come from using say, SDL.
I want to add an approach that lets you have some control over the updates. It's been a while since someone shared this with me, but from what I remember, it has something to do with ensuring a consistent update frequency.
Regardless of whether or not it's an improvement over just using a simple timer or not, having some actual code will help get you started. In addition, having the delta (to calculate the position of the ball and paddles) is something you'd have to do yourself, which this code already does for you.
Here's the meat of GameTimer:
void GameTimer::doUpdate()
{
// Update by constant amount each loop until we've used the time elapsed since the last frame.
static const qreal delta = 1.0 / mFps;
// In seconds.
qreal secondsSinceLastUpdate = mElapsedTimer.restart() * 0.001;
mRemainder += secondsSinceLastUpdate;
while (mRemainder > 0) {
emit updated(delta);
mDateTime = dateFromSimulatedTime();
mRemainder -= delta;
mSimulatedTime += delta;
}
}
It's used in C++ like this:
void DirectPather::timerUpdated(qreal delta)
{
QHashIterator<QuickEntity*, DirectPathData> it(mData);
while (it.hasNext()) {
it.next();
QuickEntity *entity = it.key();
DirectPathData pathData = it.value();
if (mSteeringAgent->steerTo(entity, pathData.targetPos, delta)) {
mData.remove(entity);
}
}
}
Since this example (quickpather) is QML-based, it has a complex setter for connecting to the timer. If you don't need stuff to be in QML like the example is, you can just create the timer in C++ and connect to its update signal directly wherever necessary:
connect(mTimer, &GameTimer::updated, foo, &MyGameObject::update);
// ...
connect(mTimer, &GameTimer::updated, bar, &MyOtherGameObject::update);
The delta is in seconds (1.0 == one second).
You can take anything you need from the example to help you get started with your game.
To answer some of your questions directly:
I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.
I wouldn't recommend doing the logic in QML/JavaScript as this game does. C++ is better suited to this (aka faster) than JavaScript. Things like scripting are well suited for JavaScript though.
Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.
My "engine" uses C++ for all of the logic (except scripts, which are kept relatively small) and QML for the GUI and also the entities (animations, sprites, etc.).
I don't think there's any documentation about this exact topic (games written in C++ with QML frontends), but there are some QML-based game examples:
http://doc.qt.io/qt-5/qtquick-demos-maroon-example.html
http://doc.qt.io/qt-5/qtquick-demos-samegame-example.html
You don't need a game loop in QML, the whole thing is event driven and powered by an underlying event loop anyway.
You can readily tap into that, use timers, signals, animations and what not out of the box.
Game loop are locking in nature. And in QML you can only use the main thread. And thou shalt not lock the main thread - it has to spin or your app will stop responding.
Why are some people cautious about using sender() in Qt programming? The typical answer is that it violates the principle of modularity of code. From the Qt documentation about pitfalls in PySide:
If you want to get the object that emitted a signal, you can do so
using QtCore.QObject.sender(), although you should really think twice
before using it (see the API docs of QObject for details). If you
really, really decide that you have to use it, be aware that right
now, you cannot call it as a static method, but only from within a
QObject slot.
As a new PySide programmer, I wouldn't consider using sender in anything but a slot, so the second concern seems almost moot.
The first reason suggests examining the API of the doc. Let's look at that. From the API docs for sender:
This function violates the object-oriented principle of modularity.
This caveat is also mentioned in Summerfield's book on PyQt, where he writes
Some programmers don’t like using sender() because they feel that it
isn’t good object-oriented style.
That's all he says.
What makes sender particularly non-modular compared to the rest of the standard practices in using PyQt/PySide/Qt? In PySide we are constantly invoking things like internalPointers in our model/view frameworks, or sneaking arguments to use in methods by making them attributes of self (effectively treating them as global variables). These and other such practices seem to technically violate modularity, and seem to be ubiquitous in GUI programming.
So why do people think sender deserves to be singled out as especially worrisome wrt modularity? Or perhaps equivalently, what is so modular about Qt programming anyway?
Overall, sender seems like an extremely useful, simple method. It is easier to use and teach others to use than things like partial functions or lambda expressions or QSignalMapper. So I can see the upside of using sender, and frankly have little grasp of the downsides that have merited their inclusion in official Qt documentation.
Generally speaking, an object's slot can be invoked by no signal at all, or by any compatible signal. In the former case, there is no such thing as a sender - for example, when using QMetaObject::invokeMethod. When the slot is activated through a signal, the sender object can be of any class. The most you can expect from the sender() is that it is-a QObject, if it is anything at all.
The signal-slot mechanism is designed to decouple objects, but by depending on the sender() you're reversing this and are coupling to the sending object. This has some applications when such coupling is expected by design, say when you implement a widget hider, or when you want to taylor the slot's action to the particular instance of a related object. Outside of such limited circumstances, where coupling-by-design is desirable, the use of sender() indicates bad design and coupling for no good reason.
The documentation merely means that you should understand the purpose of the signal-slot mechanism and the benefits of decoupling in software design before you choose to introduce coupling into your design.
Lambda expressions in fact completely obviate the need for the sender() and QSignalMapper, so you are arguing against yourself there:
connect(foo, &Foo::aSignal, [&foo]{ foo.method(); });
// as opposed to
connect(foo, &Foo::aSignal, [&foo]{ qobject_cast<Foo*>(sender())->method(); });
// and also
QList<QPushButton*> buttons;
QPointer<QLabel> label;
for (int i = 0; i < buttons; ++i)
connect(buttons[i], &QAbstractButton::clicked, [i, label] {
label->setText(QString("Button %i was clicked.").arg(i+1);
});
On another note, the reasons for QSignalMapper's existence are a tad overstated anyway, since you've got the property system that you can leverage in Qt4-style code.
class Helper : public QObject {
Q_OBJECT
QPointer<QLabel> m_label;
public:
Helper(QLabel * label, QObject * parent = 0) : QObject(parent), m_label(label) {}
Q_SLOT void showIndex() {
m_label->setText(
QString("Button %i was clicked.").arg(sender()->property("index").toInt())
);
}
};
void setup(QList<QAbstractButton*> buttons) {
int i = 1;
foreach (QAbstractButton* button, buttons) {
button->setProperty("index", i++);
connect(button, SIGNAL(clicked()), helper, SLOT(showIndex());
}
}
The "internal" pointer of the QModelIndex is merely a way to carry model-specific data in the index subject to following reasonable constraints at the time it was designed and released:
broken C++ compilers (VC6!) that choked on some template uses,
poor size optimization of linked binaries that further precluded template parametrization of consumers of the index type,
pass-by-value semantics without overhead of a pimpl,
no overhead of a vtable pointer,
don't expose the hapless user to the object slicing problem.
It is a product of an era it was designed in. Sure it could be made better nowadays, without exposing the internalXxx methods to the wide public, but that's why those methods are called internal in the first place. Ultimately, if you really wish to shoot yourself in the foot, nobody's stopping you. As a consumer of the index, you're supposed to pretend that those methods aren't there. That's all there's to it.
Yes, even back in VC6 times, one could have used a dedicated pool allocator to do low-overhead pimpl for the index and similar classes. Said pool allocator could have even been leveraged to determine the runtime type of the derived classes and implement a virtual destructor mechanism without the vtable pointer overhead. Sure. But it wasn't done that way, and the decision is with us. Given the amount of explaining needed for the model implementer to safely leverage such "magic", I think the internal pointer mechanism is a tad safer bet.
I've recently seen this interesting presentation about reactive programming in Elm.
This made me wonder whether the language constructs used to implement the Mario game (in the shown presentation, and also in the picture below) can be mapped to similar high level language constructs either in pure JavaFX or in JavaFX combined with RxJava ?
In other words, would it be possible to express the Mario game implemented in Elm using the same conceptual abstractions (i.e. time dependent values) in either JavaFX alone or in JavaFX+RxJava ?
So if an experienced 1) JavaFX programmer or an experienced 2) JavaFX+RxJava+Functional programmer wants to port the Mario game from Elm to either 1) JavaFX or to 2) JavaFX+RxJava then which programmer could accomplish this task by using similar high-level abstractions as was used in Elm ?
The abstractions I have in mind for JavaFX are bindings and for JavaFX+RxJava are bindings+Observables/Subjects/Subscription.
I had a quick look at Elm and it is quite impressive (and expressive).
In Elm you construct your scene as
Signal Element
which in JavaFX would be roughly equivalent to
ObservableValue<Node>
Naive translation to JavaFX would mean that you swap the whole scene on each update, which is prohibitively costly. In Elm, Element is an immutable abstract representation of a scene node, constructed off the screen (off the DOM). It is cheap enough to recreate the whole scene graph on every update (because of immutability, it is safe to reuse unchanged branches). The root Element is rendered to DOM, but, as I understand it, only the first time the full DOM is constructed. On subsequent updates, Elm runtime runs an algorithm to compare the new root element to the old one and only modifies those parts of the DOM that need updating, which is fast enough. The same technique is used by React.js. So both Elm and React.js provide high-level functional abstraction, but use mutability under the covers for performance reasons.
With some additional syntactic noise, you can translate most Elm constructs to JavaFX (*). For example,
lift2 display Window.dimensions gameState
is equivalent to
import static org.fxmisc.EasyBind.*;
combine(Window.dimensions, gameState, display)
The missing piece is the library of immutable abstract widget representations and their efficient rendering into JavaFX scene graph.
What you could do is:
create such a widget library for JavaFX;
or even compile Elm to JavaFX (instead of HTML+JavaScript).
I would love to see either of those done.
(*) I think Elm records are very powerful and would require a lot of boilerplate in Java (or Scala).
Elm:
type Point = { x:Float, y:Float }
p = { 0.0, 0.0 }
q = { p | x <- 5.0 }
Java:
class Point {
public final float x;
public final float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public Point updateX(float x) {
return new Point(x, y);
}
public Point updateY(float y) {
return new Point(x, y);
}
}
Point p = new Point(0.0, 0.0);
Point q = p.updateX(5.0);
Scala:
case class Point(x: Float, y: Float)
val p = Point(0.0, 0.0)
val q = p.copy(x = 5.0f)
I say it is possible, without actually doing it :-)
This is only a guess as I have little experience in this field and none at all with Elm.
I think you will get closest to Elm by creating a ScalaFX wrapper for ReactFX, though you could probably also use Java 8 lambdas in combination with ReactFX rather than Scala. You will likely have to implement quite a few extensions to ReactFX as well as various other facilities to get the abstractions and elegance you desire.
Checkout Deprecating the Observer Pattern if you have not already done so. I think that it is quite relevant to this topic especially with regards to thinking about a reactive programming model as opposed to an observable model (which is what JavaFX ChangeListeners are). That said, I think if you use libraries such as ReactFX which are built upon the JavaFX property and listener frameworks, then you likely end up with the higher level abstraction of event streams that are useful for reactive programming.
Sure, you could make a Mario game in JavaFX without using ReactFX, but the code would be quite different and you would be working at a different level abstraction to that which you would be using with ReactFX. So pure JavaFX, without ReactFX would be less Elm like.
For a network layer, akka could be used to provide a reactive framework for multi-player games, this would allow you to use reactive programming top to bottom, both in your UI and in your communications system.
For the Sprite animations in the Mario sample, adopt the netopyr code for Creating a Sprite Animation with JavaFX.
For the physics calculations you could use the JBox2D library. You would need to create some kind of reactive wrapper around JBox2D to make it aware of stuff like JavaFX properties and ReactFX event streams and subscriptions. For the simplistic Mario sample, use of an external library would probably be more trouble than its worth. Instead you could use a basic home grown physics model (e.g. something like this ball animation experiment) and hook it into your reactive framework.
I advise getting in touch with Tomas Mikula, who has created ReactFX, and asking him your reactive programming for JavaFX questions. Robert Ladstätter has also done some cool stuff with ScalaFX and might be able to give you some further advice, though I don't know if he's worked with Reactive programming at all. I'd also suggest pinging the ScalaFX users forums, but I see you've already done that :-)
The Elm Mario sample is pretty simple, so I advise trying the translation to ReactFX yourself. Then I think the answer to your question will become self-evident. Now that I've written this => if you don't actually implement it and publish your solution as the correct answer, I might have to hunt you down and you wouldn't want that :-)
I'm currently comparing traditional object-oriented GUI programming with functional GUI programming for my master's thesis. In fact, one part that I am about to begin before long is using Elm to recreate a number of traditional GUI programs in JavaFX/ScalaFX. When I'm finished with that I will probably be able to give a much more precise answer but I still want to provide some generally useful pointers now.
First, there are two good papers that provide an overview of the FRP landscape, namely “A Survey on Reactive Programming“ and “Towards Reactive Programming for Object-oriented
Applications”. The former, in particular, provides a taxonomy of FRP systems that distinguishes “Siblings of FRP” and “Cousins of FRP” (alluding to their kinship to the ideas of Fran). Siblings of FRP focus on time-varying values, Cousins of FRP focus on event streams, observable collections and asynchrony and don't have primitive abstractions for the representation of time-varying values. With that distinction in mind, Elm is a Sibling of FRP and RxJava/ReactFX is a Cousin of FRP. I guess you could say they are different animals even though both are FRP systems and have overlaps, naturally.
Second, the paper “Crossing State Lines: Adapting Object-Oriented Frameworks to Functional Reactive Languages” provides a very nice and succinct summary of the differences between the FRP approach as in Elm and the traditional OOP approach as in JavaFX:
OO makes state explicit but encapsulates it, whereas state in FRP is hidden
from the programmer by the temporal abstractions of the language.
So there is a fundamentally different approach to program design. Therefore, to me it is not yet clear if and how you can achieve the “same” high-level abstractions with JavaFX(+RxJava/ReactFX) as with Elm. That does not mean it is not possible but it is not obvious on the first glance.
Finally, a general observation about Elm and its extreme “alienness” compared to the traditional OOP approach from my thesis to make the obstacles in achieving the same result in JavaFX clearer:
A lot of GUI libraries even in pure functional languages are essentially a
thin shim over an (imperative) object-oriented GUI toolkit. This means, for
example, that widgets are not pure functions. Widgets have state and therefore
an identity. If we metaphorically turn up the functional knob on a GUI toolkit's
control board to its maximal value we must arrive at a situation where even
the widgets are nothing but pure functions. Elm is such an example of a
maximally functional language and GUI toolkit at the same time. As callbacks
are all about side-effects Elm naturally does not use callbacks whatsoever for
behavior-related code but instead FRP. Where customization in a OOP language
is most often achieved with inheritance, in Elm there is only the way of
function composition...
The key point is that in Elm the views are pure functions and, basically, Elm forces you to structure the code this way. In JavaFX you aren't forced so you must deliberately take care to do it.
By the way, there is a game skeleton for Elm games like Mario. You can study it and think about how you would design your JavaFX program following this skeleton. Maybe you could even create such a skeleton for JavaFX after your studies? I'd be interested in it.
I've posed this question a year ago. Since then I have learned a thing or two about FRP. I think the answer is no, at least not easily with RX, it would be much better to use JavaFX+Sodium FRP library.
Why not (very easily) possible with RX ? Because ELM is FRP, while RX is FRP minus transactions (vaguely speaking). So practically, if someone would want to implement the Mario Game in ELM then she would have to add transactions to RX (to avoid glitches).
I've consolidated many of the useful answers and came up with my own answer below
For example, I am writing a an API Foo which needs explicit initialization and termination. (Should be language agnostic but I'm using C++ here)
class Foo
{
public:
static void InitLibrary(int someMagicInputRequiredAtRuntime);
static void TermLibrary(int someOtherInput);
};
Apparently, our library doesn't care about multi-threading, reentrancy or whatnot. Let's suppose our Init function should only be called once, calling it again with any other input would wreak havoc.
What's the best way to communicate this to my caller? I can think of two ways:
Inside InitLibrary, I assert some static variable which will blame my caller for init'ing twice.
Inside InitLibrary, I check some static variable and silently aborts if my lib has already been initialized.
Method #1 obviously is explicit, while method #2 makes it more user friendly. I am thinking that method #2 probably has the disadvantage that my caller wouldn't be aware of the fact that InitLibrary shouln't be called twice.
What would be the pros/cons of each approach? Is there a cleverer way to subvert all these?
Edit
I know that the example here is very contrived. As #daemon pointed out, I should initialized myself and not bother the caller. Practically however, there are places where I need more information to properly initialize myself (note the use of my variable name someMagicInputRequiredAtRuntime). This is not restricted to initialization/termination but other instances where the dilemma exists whether I should choose to be quote-and-quote "fault tolorent" or fail lousily.
I would definitely go for approach 1, along with an easy-to-understand exception and good documentation that explains why this fails. This will force the caller to be aware that this can happen, and the calling class can easily wrap the call in a try-catch statement if needed.
Failing silently, on the other hand, will lead your users to believe that the second call was successful (no error message, no exception) and thus they will expect that the new values are set. So when they try to do something else with Foo, they don't get the expected results. And it's darn near impossible to figure out why if they don't have access to your source code.
Serenity Prayer (modified for interfaces)
SA, grant me the assertions
to accept the things devs cannot change
the code to except the things they can,
and the conditionals to detect the difference
If the fault is in the environment, then you should try and make your code deal with it. If it is something that the developer can prevent by fixing their code, it should generate an exception.
A good approach would be to have a factory that creates an intialized library object (this would require you to wrap your library in a class). Multiple create-calls to the factory would create different objects. This way, the initialize-method would then not be a part of the public interface of the library, and the factory would manage initialization.
If there can be only one instance of the library active, make the factory check for existing instances. This would effectively make your library-object a singleton.
I would suggest that you should flag an exception if your routine cannot achieve the expected post-condition. If someone calls your init routine twice, and the system state after calling it the second time will be the same would be the same as if it had just been called once, then it is probably not necessary to throw an exception. If the system state after the second call would not match the caller's expectation, then an exception should be thrown.
In general, I think it's more helpful to think in terms of state than in terms of action. To use an analogy, an attempt to open as "write new" a file that is already open should either fail or result in a close-erase-reopen. It should not simply perform a no-op, since the program will be expecting to be writing into an empty file whose creation time matches the current time. On the other hand, trying to close a file that's already closed should generally not be considered an error, because the desire is that the file be closed.
BTW, it's often helpful to have available a "Try" version of a method that might throw an exception. It would be nice, for example, to have a Control.TryBeginInvoke available for things like update routines (if a thread-safe control property changes, the property handler would like the control to be updated if it still exists, but won't really mind if the control gets disposed; it's a little irksome not being able to avoid a first-chance exception if a control gets closed when its property is being updated).
Have a private static counter variable in your class. If it is 0 then do the logic in Init and increment the counter, If it is more than 0 then simply increment the counter. In Term do the opposite, decrement until it is 0 then do the logic.
Another way is to use a Singleton pattern, here is a sample in C++.
I guess one way to subvert this dilemma is to fulfill both camps. Ruby has the -w warning switch, it is custom for gcc users to -Wall or even -Weffc++ and Perl has taint mode. By default, these "just work," but the more careful programmer can turn on these strict settings themselves.
One example against the "always complain the slightest error" approach is HTML. Imagine how frustrated the world would be if all browsers would bark at any CSS hacks (such as drawing elements at negative coordinates).
After considering many excellent answers, I've come to this conclusion for myself: When someone sits down, my API should ideally "just work." Of course, for anyone to be involved in any domain, he needs to work at one or two level of abstractions lower than the problem he is trying to solve, which means my user must learn about my internals sooner or later. If he uses my API for long enough, he will begin to stretch the limits and too much efforts to "hide" or "encapsulate" the inner workings will only become nuisance.
I guess fault tolerance is most of the time a good thing, it's just that it's difficult to get right when the API user is stretching corner cases. I could say the best of both worlds is to provide some kind of "strict mode" so that when things don't "just work," the user can easily dissect the problem.
Of course, doing this is a lot of extra work, so I may be just talking ideals here. Practically it all comes down to the specific case and the programmer's decision.
If your language doesn't allow this error to surface statically, chances are good the error will surface only at runtime. Depending on the use of your library, this means the error won't surface until much later in development. Possibly only when shipped (again, depends on alot).
If there's no danger in silently eating an error (which isn't a real error anyway, since you catch it before anything dangerous happens), then I'd say you should silently eat it. This makes it more user friendly.
If however someMagicInputRequiredAtRuntime varies from calling to calling, I'd raise the error whenever possible, or presumably the library will not function as expected ("I init'ed the lib with value 42, but it's behaving as if I initted with 11!?").
If this Library is a static class, (a library type with no state), why not put the call to Init in the type initializer? If it is an instantiatable type, then put the call in the constructor, or in the factory method that handles instantiation.
Don;t allow public access to the Init function at all.
I think your interface is a bit too technical. No programmer want to learn what concept you have used while designing the API. Programmers want solutions for their actual problems and don't want to learn how to use an API. Nobody wants to init your API, that is something that the API should handle in the background as far as possible. Find a good abstraction that shields the developer from as much low-level technical stuff as possible. That implies, that the API should be fault tolerant.
I was reading Joel On Software today and ran across this quote:
Without understanding functional
programming, you can't invent
MapReduce, the algorithm that makes
Google so massively scalable. The
terms Map and Reduce come from Lisp
and functional programming. MapReduce
is, in retrospect, obvious to anyone
who remembers from their
6.001-equivalent programming class that purely functional programs have
no side effects and are thus trivially
parallelizable.
What does he mean when he says functional programs have no side effects? And how does this make parallelizing trivial?
What does he mean when he says
functional programs have no side
effects?
Most people think of programming as creating variables, assigning them values, adding things to lists, etc. Variables "vary", hence the name.
Functional programming is a style of designing programs to eliminate variables -- everything is a constant or readonly.
When Joel says functional programs have no side-effects, there's a lot of hand-waving involved since its perfectly easy to write functional programs which do modify variables -- but largely, when people talk about functional programming, they mean programs which don't hold any modifiable state.
"But Juliet! How can write a useful program if it can't modify anything"
Good question!
You "modify" things by creating a new instance of your object with modified state. For example:
class Customer
{
public string Id { get; private set; }
public string Name { get; private set; }
public Customer(string id, string name)
{
this.Id = id;
this.Name = name;
}
public Customer SetName(string name)
{
// returns a new customer with the given name
return new Customer(this.Id, name);
}
}
So all the initialization take place in the constructor, and we can't modify the object ever again -- we create new instances with our modifications passed into the constructor.
You'll be surprised how far you can carry this style of programming.
"But Juliet!? How can this possibly be efficient with all this copying?"
The trick is realizing that you don't have to copy your entire object graph, only the parts which have changed. If parts of your object graph haven't changed, can reuse it in your new object (copy the pointer, don't new up a new instance of any objects in that part of the graph).
You'll be surprised how far you can carry this style of programming. In fact, its extremely easy to write immutable versions of many common data structures -- like immutable Avl Trees, red-black trees, many kinds of heaps, etc. See here for an implementation of an immutable treap.
In most cases, the immutable version of a data structure has the same computational complexity for insert/lookup/delete as its mutable counterparts. The only difference is that inserting returns a new version of your data structure without modifying the original one.
And how does this make parallelizing
trivial?
Think about it: if you have an immutable tree or any other data structure, then you can two threads inserting, removing, and lookup up items in the tree without needing to take a lock. Since the tree is immutable, its not possible for one thread to put the object in an invalid state under another thread's nose -- so we eliminate a whole class of multithreading errors related to race conditions. Since we don't have race-conditions, we don't have any need for locks, so we also eliminate a whole class of errors related to deadlocking.
Because immutable objects are intrinsically thread-safe, they're said to make concurrency "trivial". But that's only really half the story. There are times when we need changes in one thread to be visible to another - so how do we do that with immutable objects?
The trick is to re-think our concurrency model. Instead of having two threads sharing state with one another, we think of threads as being a kind of mailbox which can send and receive messages.
So if thread A has a pointer to thread B, it can pass a message -- the updated data structure -- to thread B, where thread B merges its copy with the data structure with the copy in the message it received. Its also possible for a thread to pass itself as a message, so that Thread A sends itself to Thread B, then thread B sends a message back to Thread A via the pointer it received.
Believe me, the strategy above makes concurrent programming 1000x easier than locks on mutable state. So the important part of Joel's comment: "Without understanding functional programming, you can't invent MapReduce, the algorithm that makes Google so massively scalable."
Traditional locking doesn't scale well because, in order to lock an object, you need to have a reference to its pointer -- the locked object needs to be in the same memory as the object doing the locking. You can't obtain a lock on an object across processes.
But think about the message passing model above: threads are passing messages two and from one another. Is there really a difference between passing a message to a thread in the same process vs passing a message to thread listening on some IP address? Not really. And its exactly because threads can send and receive messages across the process boundary that message passing scales as well as it does, because its not bound to a single machine, you can have your app running across as many machines as needed.
(For what its worth, you can implement message passing using mutable messages, its just that no one ever wants to because a thread can't do anything to the message without locking it -- which we already know is full of problems. So immutable is the default way to go when you're using message passing concurrency.)
Although its very high level and glosses over a lot of actual implementation detail, the principles above are exactly how Google's MapReduce can scale pretty much indefinitely.
See also: http://www.defmacro.org/ramblings/fp.html
Let me wikipedia it for you
In brief, a pure function is one that calculate things based only on its given arguments and returns a result.
Writing something to the screen or changing a global variable (or a data member) is a side effect. Relying on data other than that given in an argument also makes your function non-pure although it is not a side effect.
Writing a "pure function" makes it easier to invoke many instances of it in parallel. That's mainly because being pure, you can be sure it doesn't effect the outside world and doesn't rely on outside information.
Functional programming aims to create functions that are dependent only on their inputs, and do not change state elsewhere in the system (ie, do not have side-effects to their execution).
This means, among other things, that they are idempotent: the same function can be run many times over the same input, and since it has no side-effects you don't care how many times it's run. This is good for parallelization, because it means that you don't have to create a lot of overhead to keep track of whether a particular node crashes.
Of course, in the real world, it's hard to keep side-effects out of your programs (ie, writing to a file). So real-world programs tend to be a combination of functional and non-functional portions.
Units of functional programs have only their input and their output, no internal state. This lack of internal state means that you can put the functional modules on any number of cores/nodes, without having to worry about having the previous calculation in the module affecting the next.
I believe what he means is that purely functional code makes explicit the flow of data through the program. Side-effects allow portions of the code to "communicate" in ways that are difficult to analyze.
Without side-effects in play, the runtime environment can determine how to best decompose the code into parallelism according to the structure of the functional code.
This would be a simplification of the reality, because there is also an issue of decomposing the code into "chunks" which amount to approximately equal "effort." This requires a human to write the functional code in such a way that it will decompose reasonably when parallelized.