
Lessons learned from implementing a text editor related to front-end development - mxstbr
http://lpan.io/what-i-learnt-from-viw/
======
zellyn
I'd like to post a purely positive, encouraging comment here :-)

Thanks for the article, and good job implementing an entire editor from
scratch in C! That's impressive.

Also, as a very accomplished programmer who happens not to have done much
recent UI programming, who has read quite a bit about React/Redux/Rewhatever,
Elm, The Haskell School of Expression, etc., I find articles like this
extremely helpful: you took a simple example, and clearly and
straightforwardly demonstrated the underlying goals and principles of
"Unidirectional UI". While I mostly "get it" already from reading articles on
React-based architectures, clear reiterations of the idea are a huge aid in
getting the concepts solid.

~~~
fnl
Thank you, for this! I could not say it better/nicer. I was getting upset with
the overwhelming negativity here. Monday morning syndrome?

~~~
olddevanon
It's because the challenge he set himself isn't hard and he didn't do a
particularly good job of it either (other comments have covered that so I wont
reiterate it) yet he is soapboxing his experiences as if the topic isn't
entry-level stuff. And I mean "entry-level" quite literally as you learn about
event-driven programming in high school or equivalent IT classes. This isn't
something you need a CS degree to learn.

I mean kudos to the guy for trying something new but honestly I'd expect
anyone working as a developer in IT to have learned this much before calling
themselves a professional. And that includes Javascript devs since so much of
frontend development is event-driven anyway.

Personally I get a little fed up by just how _bad_ many frontend developers
seem to be these days. I'm not tarring everyone with the same brush as I'm
known some really amazing frontend devs too (though they ususally consider
themselves full stack). But I've lost count of the number of Javascript
developers who I've had to explain HTTP status codes and the difference
between GET and POST. It feels like frontend development is a place where
people go if they like the idea of coding but can't be bothered to learn how
to actually programme nor any of the principles they're building their code on
top of. Thankfully the topic author bucks that trend a little but even in his
case the lessons he is learning are painfully basic.

By the way it's a bank holiday (long weekend) in the UK so no Mondays blues
from me. :D

~~~
jasode
_> I'd expect anyone working as a developer in IT to have learned this much
before calling themselves a professional. _

According to author's webpage[1], he's a _" student at the University of
Waterloo, class of 2021"_.

So probably age 17 or 18. He's not passing himself off as a "professional".

If majority of HN readers feel this article was beneath their skill level and
a waste of time, that's more on the submitter (mxstbr) for misjudging its
value to the HN audience rather than the article's author.

(Although at this time, the article does have 110 upvotes while
simultaneously, the top-voted comment (poster mmjaa) is critical about its
simplistic banality. So maybe the submitter got the pulse correct for half of
the HN split-personality?)

[1] [http://lpan.io/](http://lpan.io/)

~~~
olddevanon
> _According to author 's webpage[1], he's a "student at the University of
> Waterloo, class of 2021"._

> _So probably age 17 or 18. He 's not passing himself off as a
> "professional"._

Fair enough, though I am still surprised he hadn't learned that in formal
education already. I was taught about event driven programming before I got to
university. The schools I went to weren't particularly good either so it's not
like I had a "better" education or come from privilege.

Maybe they just don't teach event-driven programming any more? :(

~~~
robotresearcher
Most students have close to zero programming training of any kind before
getting to university in Canada.

~~~
olddevanon
Maybe this is where regional differences come out as most students in the UK
have had _some_ programming lessons before starting uni (albeit they often
haven't done any recreational programming).

That was my observations at the time anyway. Things may have changed and/or I
might have introduced selection bias by hanging around with the nerdier kids.
Who knows - too late to find out now.

~~~
Silhouette
_Maybe this is where regional differences come out as most students in the UK
have had some programming lessons before starting uni_

At the level of professional-standard software architecture for UIs?

There have been some positive efforts in the UK over the past few years to
introduce programming as a more serious subject at secondary school level
(roughly, ages 11-18). I think it's great if kids get to write a simple mobile
app to chat with their friends or make a simple game, instead of only learning
things like how to use a word processor or graphics program. I think it's
great if there are teachers in schools who themselves have the skills and
knowledge to help the kids do that, too.

However, there are plenty of new starters entering the industry who have just
graduated with _degrees_ in CS or related subjects from good universities and
still won't have been exposed to these kinds of ideas at more than a trivial
level. I'd be surprised and impressed if I had a school-leaver turn up for an
interview for a programming position with more than a passing knowledge of
these subjects.

For what it's worth, I don't think the original author does themselves any
favours by inflating their experience as they do. The way they describe
themselves in the introduction on their web site seems rather out of
proportion to their actual experience, and their CV _screams_ "I read a guide
to how to write impressive-sounding CVs and I'm trying way too hard". But as a
card-carrying member of the "I thought I knew everything at the start of my
career and tried way too hard" club, I think you just have to see that as a
combination of genuine enthusiasm and understandable immaturity, and give them
credit for having a go and sharing their experience. I'm happy to see someone
at that stage in their development taking an interest and spending the time to
experiment and discuss and learn, and surely we should all be encouraging the
next generation of programmers along that path?

------
arximboldi
Very interesting work! It seems that educational text editors are becoming a
trend after Antirez published his :-)

Excuse me the shameless plug, I'd like to show mine too:
[https://github.com/arximboldi/ewig](https://github.com/arximboldi/ewig)

It is written in C++, but using a style that is unlike what most C++
developers use: it is composed mostly of pure functions. The architecture is
very much like that of Elm programs, and there is even a `store` class like in
Redux.

Like the project from OP, it is about 2K lines of code. But it also supports
asynchronous loading/saving, copy-paste (you can copy-paste a 1GB file
instantly), very robust undo, dirty markers, UTF-8 (not perfect), etc.

The magic? Immutable vectors based on RRB-Trees. This is like the vectors in
Clojure/Scala, but also supports log(n) slicing, concatenations, insertions---
these operations are fundamental for a text editor, and I'd say, to most
interactive software supporting big data models [1].

The code has been written in a style as simple as I could. I'd like to think
that even non-C++ developers might be able to understand it. It might be
specially interesting for web developers invested in Clojure, Elm or Redux and
the single-atom architecture.

Probably one day I should go ahead and just write a blog post about it or a
tutorial or something. But so far I don't have a blog I am not really a social
media person. The code is still moving also...

PS. And thanks a lot to @kostspielig her help writing and reviewieng the code!
<3

[1] The data-structure can be found here:
[https://github.com/arximboldi/immer](https://github.com/arximboldi/immer)

~~~
jnbiche
Awesome project, you're inspiring me to pick back up a text editor project I
had started to learn Rust a while back. Yours is much more featureful,
however!

By the way, if anyone else is thinking about doing the same, HN had a great
discussion on an article (also very useful) on the various data structures one
can use for text editors:
[https://news.ycombinator.com/item?id=11244103](https://news.ycombinator.com/item?id=11244103)

~~~
arximboldi
Thanks for the link and the encouragement! You have your Rust project
somewhere online? I'd love to take a look at it.

I sometimes fantasize about rewriting Ewig in Rust, as a learning project
(have been reading about it but didn't dare to write code in it yet). But I'd
like to use RRB-Vector there too. Sadly, this data-structure is not really
trivial to implement... (the concat algorithm in particular). Maybe one day
I'll find the time :-)

~~~
jnbiche
It's not on a public repo, and I abandoned it half-done a couple of years ago
while using Rust Nightly, so it will need some work I think to run on current
Rust. I stopped because I got frustrated and confused with Rust's lifetimes,
and just quit Rust for over a year.

Fortunately, a few months ago, after another attempt at Rust writing a simple
ML-like language, something clicked and now I'm enjoying writing Rust. If you
do attempt Rust, just expect to be frustrated for a while with Rust's
ownership system, it's a new concept for almost everyone. I think it's kind of
like monads in Haskell, you struggle with it until suddenly it "clicks" and
then it doesn't seem very hard, but it then becomes hard to convey your
understanding to someone else.

Rewriting Ewig in Rust, including the persistent tree-based immutable vector,
would be an excellent exercise. Indeed, just starting with the RRB-Vector
would be a great project. By the way, your immutable data structures library
is quite impressive, it would be nice to have such a library in Rust. As far
as I know, there is no such maintained library of functional data structures
in Rust.

------
agentultra
> In other words, UI programming is about mapping incoming events to a series
> of effects.

Sort of like programming with _Monads_.

This is one of the reasons why programming with Monads is so powerful: the
programmer can explicitly compose and control effects.

Good on the author for digging in and learning new things. I'd recommend
following up with reading the source to vi and doing some research on
programming patterns of the day. One of the things we're pretty bad at
preserving is context; it'd be neat to read about what the author discovers
(ie: why was vi written the way it was? What did the original authors
discover? etc).

~~~
mstade
I've tried to push pretty hard for writing rationales for any project we make,
and we've also tried to adopt making records of "big decisions" including a
tl;dr of the context. Unfortunately, these tend to take a backseat to "moving
tickets from left to right on a board" and in prioritizing what gets on the
board, unfortunately writing things down for posterity simply never makes the
cut. :o(

~~~
agentultra
Those who cannot remember the past are doomed to repeat it.

And as I like to say: software is built in the image of the organization and
processes that created it.

If the organization I work for doesn't openly condone it I still journal what
I work on and spend time on documentation and specifications before we work on
an important feature or project.

If we make a mistake or forget why a certain architectural decision was made
I've found it immensely helpful to have context for those decisions. It helps
make planning changes much easier.

------
dreta
It's worrying how sometimes the most basic programming concepts can appear
revolutionary to web developers. So much so, they've recently stumbled across
the concept of a read input-update-render loop, and are now trying, with
frameworks like React, to contort the DOM tree, just to get back to how UI was
programmed since decades.

There's a fairly old concept called "immediate mode UI", which even gets rid
of the tree structure, and keeps the whole state on the user side, giving you
full control over when elements are updated and where they are placed. These
days it's used mostly in video games, since they already rely on a 60 FPS
loop, and the UI complexity tends to be low.

If not for the necessity to use standard platform form elements due to their
various quirks and interactions with the system, I'd be doing UI programming
only in immediate mode with custom controls, simply because how convenient,
and simple it is.

~~~
nevon
I don't know how many times my colleagues and I have half-jokingly suggested
just throwing out most HTML and CSS and just draw everything to a canvas.

~~~
pjmlp
Well, that is the approach of the new Fitbit smartwatch.

It makes use of only SVG, CSS and JavaScript.

~~~
z3t4
The Canvas is much more fun and easier to work with then SVG though.

------
jmaygarden
Storing every character in a doubly linked list seems like an extremely
inefficient use of memory. Depending on your architecture, that could use 24
bytes per ASCII character (if the char in the struct is padded with 64-bit
pointers). I imagine that vi wouldn't have gotten very far if it had been that
memory constrained.

~~~
coldtea
2MB of characters in Atom use 300MB of memory or more, so it's like 150/1 --
compared to 32/8 that's nothing.

~~~
jmaygarden
OK, but Atom isn't pitched as a "lightweight vi." If I want to ssh into an
embedded device and view a 2MB log file, then I sure wouldn't want that to
require 300MB of RAM.

------
alkonaut
Is the (pseudo?) code there for state mutation representative of a widely used
pattern? It looks like using a pattern from a functional programming book, but
applied to mutable data. What I mean is this snippet:

    
    
        function handleAddTodo(state) {
           if (!newTodoField) {
             state.error = 'Empty field!'
           }
    
           state.todos.push(state.newTodoField)
           state.newTodoField = nil
    
           return state;
        }
    

This looks like a function newState = fun(oldState) but there is one huge
problem: the new state is the _same_ data as the old state? In a Rust-like
type system this might be OK because you couldn't accidentally keep using the
original state after sending it to this method, and in an immutable scenario
there would be no problem because you created a new state instead of mutating.
But this looks exactly like mutating the argument sent to a function. So out
of curiosity, do any modern UI frameworks in JS (this looks like that type of
code) do this, or was it just an unfortunate example?

~~~
1_player
Vuex works like this: you actually mutate the state instead of creating a new
one as it's expected with Redux. But this mutation takes place is a single,
controlled place (in the store mutation functions), so you get the benefit of
centralising the state management code and avoid the cumbersome immutable
transformations patterns which Redux requires.

That said, after having worked with Vuex, I much prefer the immutable newState
= f(oldState) pattern used with Redux.

------
pier25
Once you move to making mobile or desktop front end you appreciate how easy
front end web dev really is.

Contrary to popular opinion I think the DOM, HTML, and CSS, are an awesome way
of defining and styling a scene graph. When I did some C++ front end I missed
them every day.

~~~
pjmlp
I bet you didn't use any of VCL, Windows Forms, QML or XAML on your C++ front
end.

~~~
nodivbyzero
How about MFC or WTF or WinAPI?

~~~
pjmlp
They are good if one likes to write boilerplate with lots of C style coding in
a C++ application.

MFC always suffered from not being as high level as OWL or VCL, because the
internal devs at Microsoft thought that Afx (the original implementation) was
too high level.

By WTF, I think you actually mean WTL, which is based on ATL, full of
templates and low level COM style programming. Another one that gives no
pleasure using.

WinAPI was already out of fashion on the Win16 bit days, I was already using
Turbo/Borland C++ with OWL on those days.

The only reason to use Win16 directly was to wrap APIs not exposed to OWL.

Sadly due to how Borland got themselves mismanaged, OWL lost to MFC in the
early 32 bit days, and only enterprise customers with deep pockets adopted C++
Builder with VCL, which allows for VB/Delphi style programming with C++.

------
dmlhllnd
For anyone interested in building a text editor, I really enjoyed working over
this tutorial:

[http://viewsourcecode.org/snaptoken/kilo/](http://viewsourcecode.org/snaptoken/kilo/)

The author builds a terminal-based text editor in C from scratch. It's very
well written and the incremental diff-style format makes it easy to follow
along.

------
agumonkey
not C, but probably very C useful
[http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-
to...](http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-
strings/)

~~~
josephg
I made one of those in C, using skip lists instead of trees so it wouldn't
need rebalancing:

[https://github.com/josephg/librope](https://github.com/josephg/librope)

It could happily do 5M random single character edits / second on my old
laptop. Its wild what you can pull off with C. Much more memory efficient too
(it uses about 4 pointers of overhead per 180 characters).

I'd love to see a version which supported traversal using more methods though
- that library needs to support searching by line as well as character count.

I tried porting it to Rust a few times but unfortunately couldn't figure out
how to port it without introducing indirection everywhere. Modern 'C
replacement' languages don't let you do the same funky memory management
tricks. (Like using a dynamically sized array at the end of a struct allocated
in the same block.)

~~~
smaddox
Implementing efficient datastructures in Rust often requires `unsafe` code.
Unlike in C, though, you can use Traits (which provide both static and dynamic
dispatch, depending on usage) to provide a safe, zero-cost interface.

~~~
josephg
Even using unsafe I couldn't figure out how to pull it off in rust without
doubling my heap allocations.

Each item in the skip list has an associated randomly sized list of next
pointers. In C I store that list at the end of the node data structure, and
dynamically allocate the struct based on how much memory I need (basically,
size of static array of characters + size of dynamic nexts array). In Rust in
theory I can make my struct unsized to do the same thing. (Well, it pushes the
nexts height out into the pointer but that's not too bad). But there doesn't
seem to be any syntax to initialise the values in my unsized struct array
itself once I've allocated it - even in unsafe.

If you can figure out simply how to initialize a custom heap-allocated unsized
struct I'll happily keep working on it. My conclusion at the time (and, still,
after trying out tokio) is that rust isn't mature enough to replace C yet.

------
disquist
I am a novice in this area, so forgive me if I am missing something, but I
have some questions regarding the two approaches in the article, specifically
if there is a performance trade-off being made between them.

To my untrained eye, the initial version seems to be doing a minimal set of
updates based on the input it receives, whereas the latter version will call
the monolithic render procedure no matter how small a change is made to the
state.

Does each of the sub-procedures in renderTodo! check internally if the state
actually changed (by keeping a copy of the previous state?), or do they just
unconditionally re-render the entire UI? If the latter is true, then doesn't
this supposedly better way of structuring code come with a large performance
penalty? Or is it simply the case that this penalty is outweighed by the added
test-ability and improved consistency of the state?

I believe that React and similar frameworks run a diffing procedure to find
out which parts of the UI actually need to be updated (so a more minimal set
of updates is actually applied). In the first version, however, it seems like
the same diff occurred naturally as part of the code's structure - only a
subset of the render* functions are called - and therefore the diff does not
need to be computed at run-time.

Is this something worth being concerned about, or is letting the framework
compute the diff on every state change not that big of a deal?

~~~
mercurial
> I believe that React and similar frameworks run a diffing procedure to find
> out which parts of the UI actually need to be updated (so a more minimal set
> of updates is actually applied)

That's true. React diffs the virtual DOM and applies the changes to the actual
DOM. However, the fastest is still to diff the actual data to be rendered, and
determine whether the render function needs to run at all (this is opt-in via
React's shouldComponentUpdate() lifecycle method).

------
scarface74
So this guy has rediscovered how we did GUI development back in 80s and early
90s?

~~~
robotresearcher
Yes. He's a student. It's cool.

------
skywal_l
What is the difference between Event Sourcing and the Command Pattern here?
For decades the Undo/Redo functionality has been implemented by the Command
Pattern it seems. And looking at what Event Sourcing is, it looks a lot like
the Command Pattern which purpose is to encapsulate into an object a side-
effect performed on some data structure. That object can then be executed at a
later time, reverted, logged, etc...

------
WalterBright
Another C tty oriented text editor is the classic MicroEmacs:

[https://github.com/DigitalMars/me](https://github.com/DigitalMars/me)

I learned a lot about programming from reading the source code to it. It's a
gem of clarity and design (and you could reasonably argue that many of my
changes to it messed it up).

------
zoom6628
All i can say is "watch this kid!". He is showing the motivation,
perspectives, insight and intelligence to be able to do important work in the
future. Great article and the C code worth reading to learn from. Thanks for
sharing and looking forward to reading future blogs and seeing what you
create.

------
innocenat
> In other words, UI programming is about mapping incoming events to a series
> of effects.

So I guess the word `event-driving programming` is lost in time.

And I don't think the Unidirectional pattern described is suits for C
programming. When I see people use C, I think performance, and unless the
compiler optimized it away the state mutating function is gonna cost a lot of
unnecessary memory copy. And worst offender is that unless you have React-like
UI diff-ing library, it's gonna be a costly entire screen redraw event for the
most simple update.

~~~
DSMan195276
> unless you have React-like UI diff-ing library, it's gonna be a costly
> entire screen redraw event for the most simple update.

He's using ncurses, which actually does that - it only redraws the parts of
the screen that change. It can require a bit of coxing at times to ensure that
things get redrawn properly but I'm pretty sure he's good - I didn't see
anything in his code that would force a full redraw every update.

~~~
radarsat1
> He's using ncurses, which actually does that - it only redraws the parts of
> the screen that change.

Heh, when I first read about React, my immediate reaction was like, "oh so
it's like ncurses for the web, cool, makes sense."

------
YSFEJ4SWJUVU6
A cursory look into the linked github pull request changes made me spot this,
and I must admit that never in a million years would I've thought to erase the
possible endline character of a string returned by getline with this:

    
    
      line[strcspn(line, "\n")] = 0;
    

I don't think I'm going to start, either, even if it is a nifty oneliner.
Anyway, I've always found this kind of little projects a good sport.

~~~
eplanit
Wise choice.

~~~
YSFEJ4SWJUVU6
That's not correct. If the scanned string doesn't contain any of the search
string's characters, strcspn will behave like strlen, and the snippet ends up
doing effectively nothing.

However, the statement is inefficient in what it does (and even then, not the
most obvious way to achieve that, which your comment also highlights in a
roundabout way).

------
jnbiche
Nice article, good summary of the purpose of unidirectional UI approach like
Redux's, although it doesn't get as much into persistent data structures as
maybe it could have.

What's the point of the exclamation mark after certain function names? Is that
a pseudocode thing? Is that supposed to be shorthand for an impure function?
(if so, not sure why `handleKeyboardEvent` doesn't have an exclamation mark.

------
mmjaa
The more I read, the more I felt that the author was long-windedly discovering
FSM's, only describing them using the language de-jour - i.e. JavaScript-
ecosystem-ism's.

Is this the state of things today - that kids start off as highfalutin'
"developers", whereby 95% of their apps are written by others (because: "npm
-i <all the things>"), and then .. eventually, from the top-down, trickle
through the stack learning "the things", giving it all a new fancy name, and
blogging about it? Because to me, this seems more like devolution at work in
the computer science industries, not some kind of radically derived insight.

I'm not trying to be overly critical, but for a lot of us, "discovering that
C-based apps are, weirdly, similar to what us React-ites are doing" sure seems
like a step backwards from real stack competency.

~~~
keyle
It's true that today's devs are glorified plumbers.

On the other hand, so much gets done, it would be insane to go back to "C for
all the things!".

It's a trade off, you're either a high level hacker, piping stuff together and
watching for leaks, or your a low level system guy, squeezing the carpet.

~~~
mmjaa
I would argue that a lot more of the worlds productive plumbing depends on
C-based apps/libraries/frameworks than we would care to admit - its just that
its 'not sexy' enough for the young-uns to get behind and start using, since
everyone knows that C is a greybeard language and, therefore, not cool.

The same argument ("so much gets done") was made for Visual Basic back in the
day, you know. Oh, how the hoipolloi cried and crowed for the death of C
developers back then. Oh, how they were wrong, oh so wrong!

I'm not saying the world doesn't have a debt to pay to the Node/Javascript
camp - it surely does. I just feel that there is something really missing in
the scene, if in fact things that C developers knew and applied well 'back in
the day' are just now being re-discovered as "Cool New Shit™" by those who
chose - willingly - to ignore the very mechanics of the components their
stacks are highly dependent on.

Still, I guess its not worth complaining. Its good to know that JS guys can
get over the wall, and discover that we've all been using state machines for
decades now, and so on, eventually. I just wish there was a lot less hubris on
the "crowing about it" side of things. Honestly, JS guys: you should know a
little C. Its still there, underneath all the cool shit, and you're still
heavily, heavily dependent on it, no matter what your "npm up" tells you...

~~~
tcfunk
In my purely anecdotal experience, learning web-based technology over C/C++
was not a choice I made personally. It was a career path that was foisted upon
me by job availability and hiring requirements.

I have yet to see a job posting for a fresh-off-the-boat C developer. It's
nearly always 5-10 years industry-related experience required. Web, on the
other hand, seems more willing to take on the new guys.

~~~
vostok
I think they're more willing to take new people mostly because there are more
jobs and not enough programmers in Web.

------
crummy
I'm new to frontend development. Is this kind of how Vue works?

------
mi100hael
Dat JavaScript coding style

------
jboons
If you plan on allowing future employers to look at your Github profile, you
might want to change the way you write your commit messages.

> REFACTOR: :hocho: future queue (I was retarded)

Not exactly an appealing commit message.

------
alacombe
It is not surprising that C gets that much of a bad reputation when devoloper
show such poor capacity at managing errors; malloc(3) return values are never
checked and everything is expected to always succeed, throughout the source
tree.

~~~
baybal2
Competent C devs are rare these days. Just too many did retire. At the very
start of my professional career I thought of becoming embedded dev, but I was
disheartened by the job market.

The very few jobs I found were like "Senior C dev, minimum 7 years subject
matter experience, $65k" at the time when web dev roles were paying 85k+ and
were so easy and dumb...

What distinguishes a good C developer? A high self discipline. That language
gives you a lot of ways to introduce bugs, but unlike JS you do have clear
realisation why they appear most of the time.

~~~
hackits
You can use my own experience as a little bit of anecdotal evidence. I started
out of collegue and started programming in C/C++ as a game dev. I started at
40K AUD in Sydney in 2002 just before the housing boom here in Australia.
Granted stayed with the business for 4 years. During the time my colleges got
a job in web development CRUD application systems for the web. Their starting
salary was 85K.

I remember walking into the CTO/CEO office at the time asking how much they
valued experienced C/C++ developers. They honestly said at the time that
(frank) who had 10+ years doing game dev they couldn't see any point in paying
him anymore than 60K a year. I thanked them for their time and went back to my
desk.

Next day I walked in and handed in my resignation. Both the CEO/CTO was
shocked. The next week I walked into a web development shop
(oracle/java/javascript) and tripped my salary.

~~~
sbov
Game dev is built on the backs of people sacrificing salary for "working in
games". You really can't compare it to any other job. All my friends who
worked with C/C++ in game dev that moved out of game dev, but still used
C/C++, at least doubled their salary.

~~~
hackits
A job is a job. For me the simple truth of the matter is I couldn't support
the quality of life I wanted to live working in games and the salary and
rewards they where offering. It was fun, but going back to C/C++ is something
I would avoid at all costs, although if the salary doubled over night I would
put up with C++ although I think I would take up drinking.

