Sorry about the huge message, I hadn't checked email in a few days.
Date: Tue, 22 Feb 2011 12:37:18 +1100
From: john skaller <***@users.sourceforge.net>
To: SDL Development List <***@lists.libsdl.org>
Subject: Re: [SDL] text input and key down events
Message-ID:
<27D6BFA9-3C52-48A7-9BF2-***@users.sourceforge.net>
Content-Type: text/plain; charset=us-ascii
Post by john skallerPost by Jeff PostThe way I handle it is to define a general widget type (structure or class,
depending on language). Then each widget (text input, text output, file
selector, etc) attaches callbacks for the types of events they need to
handle. Events are processed by passing them to a processCallBack function
which runs through the widget list and passes the event to the callback
function for the topmost widget in the list that has registered a callback
function for that type of event. The widget that processes the event then
becomes the topmost widget.
That's quite a sane algorithm, although it has one problem: callbacks.
Hard to avoid in C.
Callbacks suck because you lose the stack: your per-widget code becomes
a slave of the event loop.
There are two ways around this. One is to use threads. This also sucks
because it is overkill (consumes resources).
The other is to use a better language :) I think (not sure) Go has channels
You don't sound like you use C very much. There's one truly good way
to give C callbacks closure: a void pointer. Example function
prototype:
int accumulate( void *closure, int value );
If you need to dynamically resize the closure, and you don't want to
have another pointer inside of the closure, then you'd do this:
int accumulate( void **closure, int value );
I won't claim to be a big fan of C's pointer syntax (though the syntax
itself is my only real problem with pointers), but it works, it
reflects the way things really work (which is good for a 'portable
assembly language' like C), and it's a simple way to enable
reentrancy.
Post by john skallerIt's a great pity some of the API's SDL uses are forced to be callback
driven (Audio I believe). The really big advantage of SDL is that
it is a library NOT a framework that forces you to do everything with
callbacks.
The relevant structure is this:
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in samples
(power of 2) */
Uint16 padding; /**< Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback;
void *userdata;
} SDL_AudioSpec;
It's in include/SDL_audio.h. I've separated out the two relevant data
members: callback and userdata. You get to supply both, and userdata
is used as one of the arguments when callback is called. You then cast
it in the function to whatever type you want. For example, if you were
writing in C++, you would probably cast it to an object, and then call
a member function of that object. A binding for another language (for
example, a functional language) would likely do the same.
------------------------------
Date: Wed, 23 Feb 2011 00:41:58 +1100
From: john skaller <***@users.sourceforge.net>
To: SDL Development List <***@lists.libsdl.org>
Subject: Re: [SDL] text input and key down events
Message-ID:
<8E170E52-9BCC-4C48-8471-***@users.sourceforge.net>
Content-Type: text/plain; charset=us-ascii
Post by john skallerPost by Jeff PostPost by john skallerThat's quite a sane algorithm, although it has one problem: callbacks.
Hard to avoid in C.
Callbacks suck because you lose the stack: your per-widget code becomes
a slave of the event loop.
Not a problem in the applications I write. Don't know about games though since
I don't write games.
i don't mean to be offensive but ..
"I am fine with assembler I don't need high level languages"
"I think gotos are just fine, I don't need block structured programming languages"
"Procedural code is fine, I don't need functional programming"
"I am happy with object orientation".
This one I do actually object to, with a caveat: A shift from a
language that supports operator-overloading for objects to ANYTHING
that doesn't is a genuine downgrade (No, I'm not a fan of Java, though
I do UNDERSTAND why they didn't include this particular feature).
Post by john skaller"I am fine with callbacks"
Its all the same. You don't understand why what you're doing is bad, you're
used to it and you think it is ok.
It isn't OK.
Actually, it is okay. You need to remember: C is the most portable
assembly language known to man. Certain dialects of Forth might rival
it, but I'm not certain that even those do, and Forth is barely
structured (in fact, does it actually count as structured?).
Post by john skallerPost by Jeff PostPost by john skallerBut they're not. The execution model of the underlying code
is callbacks.
Uh, okay. Then I fail to see the difference.
You can't see the difference between C and machine code?
It's called automation: the compiler (in both cases) does a lot
of tedious housework for you and gets it right every time (hopefully :)
This is what language bindings exist for: to abstract concepts that
are appropriate for the language that the bound code interfaces
through, but either not appropriate or needlessly inconvenient in
another language that uses said interface.
Post by john skallerPost by Jeff PostPost by john skallerBTW: to understand how important control inversion is, think about parsing
a file with a subroutine called with a single character at a time, as
opposed to reading the data. When you read, you're the master. When you're
called with the data you're a slave.
Funny you should mention that. My latest application does read a file one
character at a time because it needs to parse files written on Linux (LF only
newline), Windows (CR/LF newline), and Mac (CR only newline). Whether it does
so as master or slave is not relevant to the application.
The issue isn't whether you read the file one character at a time, but whether you read
the character or are called with it.
The differences is very relevant to the complexity of the code you write.
For example analysing expressions requires recursion. To do recursion you must
have a stack.
Correct. Personally, I've found that the 'slave' model (specifically,
callback with void pointer) is very useful, because I'm parsing
character-by-character anyways. However, in other situations I've
preferred the 'master' model. It depends on the situation, and
preferring one or the other will just cause you grief.
------------------------------
Date: Wed, 23 Feb 2011 01:50:15 +1100
From: john skaller <***@users.sourceforge.net>
To: SDL Development List <***@lists.libsdl.org>
Subject: Re: [SDL] text input and key down events
Message-ID:
<6AF93FF3-C949-462C-876B-***@users.sourceforge.net>
Content-Type: text/plain; charset=us-ascii
Post by john skallerPost by Jeff PostThat depends entirely on the complexity of the grammar you're using. For a
lexer
(tokenizer,) being called one character at a time is perfectly reasonable, if a
bit
slower than optimal, and no stack is required.
It's only reasonable if the lexer is *generated* by a tool, which builds
a finite state automaton, or at least an NFA.
Actually, I'm writing a C-like parser/lexer at the moment, and with
better string functions the only really annoying thing would be the
initial comment/string parsing. Everything else is decently simple so
far, you just need to know when to do what step (note: I'm not trying
to parse C itself, it has some quirks that I disagree with, some of
which complicate parsing ;) ).
Post by john skallerThe problem isn't callbacks (Felix has callbacks! and as you point out
HOF's often use callbacks). The problem is when you're forced to use
them by a framework and your problem is complex enough you demand
the tools of higher level systems: modularity, integrated data and control
flow using a stack,
That's what bindings in other languages are for. SDL is supposed to be
portable, and thus a highly portable language is the appropriate one
to have the interface in. Bindings for other languages can then be
written to provide a behaviorally equivalent interface in the targeted
language.
Post by john skallerMost (non-arcade) games and GUI applications are complex enough that
callbacks alone just won't do.
Which is why the profesional game developers mostly moved to languages
other than C some time ago. C++ (an obese, soul-sucking monstrosity,
sure, but fast, and when using a small enough subset of it's features
understandable), Lua, Objective-C, etc. all offer feature improvements
over C, and thus have supplanted it's use in various areas.
Post by john skallerbetter technology like fibres can't be implemented without compiler
support.
Hahahahaha! Seriously, it's a hideous hack that might (AND SHOULD!)
cause your hair to fall out, BUT an extension of the C language's
setjump/longjmp facility is sufficient to implement continuations, and
therefor sufficient for both fibers that don't use globals (and
technically those too, with entrance/exit functions) and coroutines.
You have some reasonable ideas, but this bit is totally off-base.
------------------------------
Date: Tue, 22 Feb 2011 07:51:41 -0800 (PST)
From: Mason Wheeler <***@yahoo.com>
To: SDL Development List <***@lists.libsdl.org>
Subject: Re: [SDL] text input and key down events
Message-ID: <***@web161209.mail.bf1.yahoo.com>
Content-Type: text/plain; charset=us-ascii
Post by john skallerSubject: Re: [SDL] text input and key down events
Post by Jeff PostThe problem isn't callbacks (Felix has callbacks! and as you point out
HOF's often use callbacks). The problem is when you're forced to use
them by a framework and your problem is complex enough you demand
the tools of higher level systems: modularity, integrated data and control
flow using a stack, and if you go even higher level you need things like
garbage collection for memory management.
<snip>
Post by john skallerAlso, WRT garbage collection, I've never encountered any programming
problem, no matter how "high-level," that required it. I consider garbage
collection one of the worst misfeatures of all time.
It has enabled the success of many Java programmers who otherwise
would never make it in the marketplace, but I'm not certain whether
that's a mark in the 'for' column or one in the 'against' column.
Post by john skallerIt's only "necessary" in
functional languages because they're designed very poorly, based on
fundamental principles such as "let's pretend we're not *really* running
on a Turing machine." The problem with GC is that it eliminates the
perception of the need to think about memory management, without
eliminating the actual need to think about memory management, thus
eliminating quite a bit of *thinking* that is still necessary. (See
http://tinyurl.com/9ngt74 and http://tinyurl.com/4pxr822 )
GC (or rather, automatic memory management, since I consider GC to not
encompase the entirety of AMM) is fairly intrinsic to declarative
languages, since you aren't supposed to ACTUALLY know how your code
works, but you're right in that attention needs to be paid to memory
during coding, since there's no guarantee that the compiler will go
with a memory-lean alternative to your memory-hungry algorithm (or
even recognize the algorithm as you wrote it!).
Post by john skallerPost by Jeff PostAnd a second point needs to be made: better technology like fibres can't
be implemented without compiler support.
Sure it can. I just call the CreateFiber function and I'm good.
http://msdn.microsoft.com/en-us/library/ms682402%28v=vs.85%29.aspx
Amen.
Post by john skallerPost by Jeff PostGame programmers are the worst hit by bad technology because games
are the most sophisticated and difficult application around. Which is why
most games are so deficient in many ways .. most "so called" strategy games
have hardly any strategy in them, their unit routing algorithms are
non-existent or suck totally -- even though good algorithms exist --
because the programmers spend most of their time struggling to implement
basic stuff without error, because the tools they're using aren't up to
the job.
Most of that can be laid at the feet of C++. If game programmers were smart,
they'd use a language with a real object model and decent OO semantics, and
half their trouble would vanish.
It's not even C++ really, MOST of the trouble is from (at least
initial) bad implementations (e.g. VC++6), and poor libraries.
Seriously, auto_ptr was the best they could agree on? He even mentions
graphics at one point in TC++PL 2nd ed, which has never been part of
the standard.
As for the object model, what do you want, prototypes? Maybe quajects?
While C++ classes may have a few bugs in their design (I would have
preferred that classes NOT just be structs that default to private),
classes in general are appropriate for close-to-the-metal languages
like C++, dynamically extended prototype objects like in JavaScript &
co. aren't.