 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
In the film Hudson Hawk [yes, I know], Richard E. Grant can be heard to
assert that "happiness comes from the fulfilment of /goals/!" Now this
isn't a film that you should ever take too seriously. But this quote
does seem to have an air of truth about it.
It's roughly 10 years now since I seriously wrote any Java code. I often
write psuedocode using Java syntax, but it's a very long time since I
actually compiled any Java with the serious intention of /running/ it.
So I just spent the past month or so coding in Java.
The result is Logic Box, as you've all seen. I'm still not completely
happy with it, but there's definitely a sense of achievement to be
gained from actually producing a /finished/ program that does something
[vaguely approaching] useful.
On the one hand, I could have written this program in Haskell in about
half an hour. Haskell already /has/ sophisticated parsing libraries
which are trivial to use. The structural inspections are all 1-liners.
The data transformations are similarly trivial. And, of course, I've
written this program several in Haskell several times before, so I
already know the best way to factor it.
On the other hand, the Java program is a ~200KB JAR file which runs
/everywhere/. A Haskell "hello world" program compiles to 1MB on
Windows, and runs only on Windows. More to the point, my Java program
has a GUI. Sure, you can do that in Haskell, but it's a hell of a lot
more work.
For a start, you need to install GTK (the GTK developers keep moving the
damned download, and it's hard to figure out exactly which file(s) you
need), and manually add it to your search path. Oh, and I hope you
weren't using any /other/ applications that need GTK. Then you need to
get the Haskell GTK bindings to compile, which is quite a long,
convoluted dance. Oh, and Glade [the UI painted] no longer seems to be
part of the standard GTK bundle, so you need to get that separately. It
also depends on several other GTK packages which aren't really bundled
for Windows properly, so you have to fiddle with .pkg files to try to
guess what the correct settings are...
By contrast, once I have NetBeans installed, I can throw a
non-functional Java GUI together in /seconds/. Adding code to make it do
something is also fairly trivial. You /do/ have to deal with the extreme
brain-deadness of the Java APIs. But if you can fight past that, you get
to have a API application which anybody can run without having to do
some convoluted dance with installing the entire GTK runtime. (Or,
alternatively, me figuring out exactly which DLLs are required and
sending complicated instructions on where to put them.)
So the languages - and more specifically, the ecosystems in which they
exist - have different strengths and weaknesses. In Haskell, I spend
most of my time fighting the fact that Windows isn't Linux, and that C
isn't Haskell. In Java, I spend most of my time fighting the absurd
APIs, and the general stupidity of the actual programming language.
Java is a very, very, stupid language, by the way. It's a long time
since I've really done any programming with anything that isn't Haskell.
I'd forgotten just how much of my time I end up wasting typing "public
static void Log(BufferedWriter out)" and similar nonsense. But more than
that, I'd forgotten just how much time is spent trying to find
workarounds for the stupid limitations of the language, the bugs, the
glitches, the stuff that doesn't work how it's supposed to, the stuff
that isn't documented, etc.
Java has generics now. It didn't, back when I used it. One of the things
I wanted to see is what the syntax is like, and how you use it. I've
since come to the conclusion that the answer is "you don't". The system
is just too weak and feeble. Because generics was hacked in as an
afterthought, it really, really doesn't work properly. You want to
create an array who's element type is determined at run-time? Oh, I'm
sorry, that's impossible. The language does not allow it. Have you
considered using an ArrayList instead?
There's lots of other stupidity too. Java has this retarded system where
everything is a class, *except* int, long, double and bool. [OK,
actually there's a few more...] These are primitive types, which
completely different semantics. For performance reasons.
You know what that means? It means that you /cannot/ use these types
with generics. Which means that you /cannot/ use them with any of the
standard container types. Unless you wrap them, to turn them into
objects, thus negating every single one of the performance benefits
which lead them to be non-object types in the first place. THE STUPID,
IT BURNS!! >_<
Interestingly, you /can/ make arrays out of them without boxing. Because
arrays don't use generics, they use a system equivalent to generics but
hard-wired into the language from day 1, which thus ACTUALLY WORKS
PROPERLY. If they had extended this to allow you to use it for your own
classes, we'd be golden. But that would break backwards compatibility,
so noooo...
You know what? Eiffel allows you to /choose/, on a class by class basis,
whether objects of this class should have reference semantics or value
semantics. C++ allows this in a variable by variable basis. Both of
these languages manage to treat reference objects and value objects in a
consistent, uniform way that works properly with generics. But no, not
Java. :-P
Let me just back up a bit and summarise what I just said: Java sucks.
Badly. The language is complex, bloated, weak and flabby. It's a problem
that seemingly *all* mainstream languages share to some degree or
another. Which is crushingly disappointing, because mainstream languages
let you actually *do stuff*. Useful stuff. Like have GUIs, or access
multimedia data, or connect to databases, and so on.
Unfortunately, it seems that only obscure languages like Haskell are
actually well designed. But such languages suffer from it being
impossible or at least unreasonably difficult to *do* anything that
involves talking to the outside world. It's really, really frustrating
that there isn't a language that does both.
Having said all that, I /was/ eventually able to rewrite Logic Box in
Java, and it /does/ work. It's the first time I've tried to implement
Logic Box with interactive stepping. Because, let's face it, from a CLI
that would just be too horrible to be useful. But from a GUI, it's a
plausible thing to want to do.
(I did once implement Lambda Box as a CGI script, so that I could have
an interactive UI without losing my mind. It's a sad day when generating
HTML and sending it over HTTP is /easier/ than writing a native GUI...)
The actual kernel of Logic Box is not difficult to write. Just tedious.
Of course, writing a program that solves predicates as much simpler than
writing a program that shows you what it's actually doing while it does
it. In true iterative-prototyping style, I tried several different
approaches.
Initially I had an Expression class with a Unify() method, and a
Predicate class with a Solve() method. But eventually, I decided on
having a separate Solver object for each kind of predicate, and having
expressions and predicates as immutable objects, consequently with far
fewer methods.
Initially unification used a Unify() method defined in Expression and
overridden by each type of Expression class. But today it's a huge
tangle of nested if blocks using the "instanceof" operator instead. A
retrograde step, perhaps, but it works and it means that all the
unification logic is in one place instead of fifteen places that need to
cooperate intimately.
The actual solution process itself is a state machine. Initially each
Solver contained a set of variables holding the necessary data for every
possible state, most of which starts out as null or similar invalid
values. Then, in the Step() method, a complicated tangle of logic
analyses these variables and attempts to reverse-engineer the current
state by seeing what variables have and haven't been set.
This isn't a great idea. In particular, every time I add a new variable,
or change the order of states or something, the state detection code
tends to break horribly, and I spend forever chasing obscure bugs where
half the code behaves as if we're in one state, and half in another
state. The solution, obviously, is to encode the current state
/explicitly/, rather then trying to "guess" it from implicit information.
The solution cries out for first-class functions, but Java has no such
thing. Ideally, we'd have a Solver that holds all the data, and a
pointer to the Step() function. When the Step() function executes, it
updates the data in the Solver, and then updates the function pointer to
point to the next Step() function. But we can't do that, because Java
does not have functions.
Instead, every state that the state machine can be in becomes an entire
class. A private nested class (because nobody else needs to see it), but
a class none the sell. Oh, but there's some brokenness with inner
classes and disambiguating between local variables, inner class fields
and outer class fields. I wasted a lot of time sorting that one out.
I'm still not 100% happy with the result. I kept the data in the Solver
object rather than the Step object so that I could implement the GUI
display code just once. But it turns out that different states ought to
display differently, which leads to the Step object needing to "talk to"
the Solver object rather a lot, and the display code becoming very
complicated. It seems that the correct thing to do is just move
/everything/ related to a state into the actual State object.
Also, currently you can advance the simulation forwards only. I can't
tell you the number of times I've clicked the button three times and
then been like "oh, wait, go back!" But you cannot go back. This is the
beauty of destructive updates; the old state has been lost, and that's
that. I think with some work, it should be possible to allow going
backwards as well as forwards.
I /also/ think the GUI display needs some serious work. There are too
many redundant steps. The GUI displays so much information by default
that you get lost in a sea of data and it's difficult to understand
what's really /happening/. I think the display needs to be more focussed.
(Regarding redundant steps: Consider the predicate "x = 1". This has the
following steps...
1. LHS == RHS?
2. Bind x.
3. Simplify solution.
4. LHS = RHS?
5. LHS == RHS. Predicate solved!
6. Sending solution...
7. Done.
That's 7 times you need to click the Step button to solve this trivial
little predicate. Surely we can do better...)
Parsing was fun too. And by "fun" I of course mean "not fun at all". :-P
During testing, it rapidly became clear that writing half a page of Java
code every time I wanted to test a different aspect of the solver was
just not good enough. So a parser had to be developed early on.
I imagine that somebody somewhere has probably invented either a parser
library or a parser generator for Java. But I coded mine by hand. The
/lexing/ is fairly easy. (Once you get around Java's gigantic APIs to
the bits you actually want.) The /parsing/, not so much.
Initially I tried to implement parsing in Java the way you'd implement
parsing in Haskell. DON'T DO THIS! It doesn't work at all! First of all,
a monadic parser really /requires/ first-class functions. Java can
sort-of simulate these, but the result is horrifyingly complex and
inefficient. And Java's generics really, really don't work properly, so
trying to make the parser's result type a generic parameter is an
exercise in futility.
I am not well-versed in parser theory. I have no idea what the hell the
difference is between LL1, LR, LALR, top-down parsing, bottom-up
parsing, recursive descent, or whatever. I am just a humble computer
science (*cough* information technology) graduate. :-P
What I do know is that I started out with a system of "levels". Each
level takes a container of terms, and groups some of them together into
larger terms. The input to level 1 consists of single tokens. Level 1
turns anything expression-like into expressions, but leaves all other
tokens alone. Level 2 therefore receives a mixture of tokens and full
expressions. (This requires a Java analogue of Haskell's "Either" type.)
Level 3 tries to group pairs of expressions into equality predicates.
Level 4 thus receives a mixture of tokens and predicates, with no
expressions remaining.
The good news is that this frameworks makes it easy to dump the result
of a given level out onto the screen to check everything is parsing
right. The bad news is... there's quite a lot of boilerplate code, and
it's hard to get things like bracketing to work. As soon as you see an
open bracket, you need to jump to another level in the hierarchy.
The final, /working/ implementation is different. There's a function for
parsing each construct. Null is returned on EOF, otherwise an exception
is thrown if the required construct is not present. The functions for
higher precedence operators call the functions for lower precedence
operators to parse them. At the very bottom is a function which parses
an equality /or/ a bracketed predicate of any type.
Again, things get tricky when you get to AND and OR. You can tell
whether a predicate is bracketed or not by looking at the first token.
You can statically tell where equality predicates are supposed to be
situated. Exists always starts with "~". And so on. But for AND and OR,
you need to "look ahead". For this, I have to buffer tokens, so they can
be "peeked" multiple times without advancing to the next token.
Eventually I got it to work. (I'm surprised nobody has yet found a way
to break my parser. I assume nobody has bothered trying...) Only the
most recent prototype actually includes proper error reporting. All
earlier versions simply throw an exception and die if anything
unexpected ever happens. The current parser attempts to indicate /what/
actually went wrong. This is a surprisingly non-trivial task!
Later I had to go back and hack in the ability to parse named predicate
definitions. (Originally only the actual predicate in the input box was
parsed.) And to load and save predicate libraries from file. In the
process, I once again had to battle against Java's ridiculous I/O APIs.
But this, too, now works - more or less. (I really ought to add a way to
have comments though...)
Building the GUI was a somewhat frustrating exercise. The UI painter
makes it easy enough to draw what you want. Except that the UI painter
uses the "Windows" look and feel, while the generated code defaults to
the "Nimbus" look and feel, and AFAIK there is /no way/ to change this.
I actually deleted the look and feel code, so now it defaults to "Java".
This is why Logic Box looks so ugly. (In particular, the tool bar
doesn't look like a tool bar, and the separators between the buttons are
invisible.)
It took some doing to figure out how to wire up the buttons to some
executable code. NetBeans was asking me to select predefined Action
objects or some mumbo-jumbo like that. (I looked it up; apparently this
is the Swing API's way of getting around the lack of first-class
functions. So you can have a button and a menu item that do the same
thing, and you don't have to code it twice.) It turns out you can just
double-click the button, and NetBeans generates the stub method for you.
Figuring out how to work a tree was harder. As you'd expect. It seems
it's impossible to modify an existing tree. So every time you click
Step, the entire tree is deleted and rebuilt from scratch. (Probably
explains part of why Logic Box is so slow.) I also don't understand why
you cannot simply say "here is a tree". Instead, you have to have a
series of DefaultMutableTreeNode objects, then you need to create a
DefaultTreeModel object (which you cannot do until /after/ the tree
nodes are built), and finally you can pass this to the JTree object
which is the actual GUI component.
You would /think/ that DefaultMutableTreeNode would have an attribute or
a method or something which would let you select whether it is initially
expanded or collapsed. You would be wrong. Instead, you have to go to
the JTree object, pass it the TreePath to the DefaultMutableTreeNode
that you want to expand or collapse, and call either expandPath() or
collapsePath(). (No, there isn't an expandPath() method that takes a
boolean. You have to write an if-statement yourself. Every single time.)
You have to refer to the node you want to expand or collapse by path.
You cannot simply use a pointer to it. Which means you can only expand
or collapse the node once the tree is completely built (because until
then, a path doesn't exist). Which means you have to do /two/ passes
over the input tree to construct the output tree.
You would /think/ that DefaultMutableTreeNode.getPath() would return a
TreePath. You would be wrong. It returns a TreeNode[]. So what you
/actually/ have to do is
TreePath path = new TreePath(node.getPath());
Isn't that silly?
On top of that, presumably in an effort to be helpful, expandPath()
expands the selected node /and all parent nodes/. Which means to make
the expansion state of each node match what the input tree actually
requested, you have to scan the input tree bottom-up rather than
top-down. Which is just weird...
I also love how when you create a DefaultMutableTreeNode, you can select
whether this node can have children or not. You would /think/ this
dictates whether the graphic shows a folder icon or a file icon. You
would be wrong. The number of actual children dictates that. The setting
here just controls whether an exception is thrown when you try to add
children. >_<
In short, tree-building is a pain. OTOH, it turns out that you can use
HTML in the node titles. (If the title text begins "<html>".) And by
"HTML", I mean "some SGML derivative vaguely resembling HTML 2". I
quickly discovered that it really, really does not work well. For
example, if you set the background colour of some text, and inside that
span you set the foreground colour, that /cancels/ the background
colour! There is no style cascading here; if you want that, you have to
reimplement it by hand.
If you look at the "about" or "quick reference" pages, you will also see
that the general rendering quality is really quite low. (At least in
these panes, you can use real HTML with real CSS!) But hey, what do you
expect if you try to embed an entire web rendering algorithm into a GUI
library as an afterthought?
In summary, most of my time was spent wrestling with weaknesses of the
Java language, and the overly complex APIs you have to use with it. Many
of the bugs in the actual kernel are due to workarounds I had to do
because the natural way to encode the solution is impossible. It's been
a frustrating experience.
Then again, if I posted a Zip file containing a random Windows
executable and half a dozen DLLs and said "run this!", I doubt anybody
would. And I'm sure I'd be receiving a lot more reports about how broken
it is. Written in Java, this stuff actually works.
I'm still not completely happy with the GUI. It works fine for the
utterly trivial predicates I used during testing. However, trying to
write, debug and run "real" programs in it, I find it to be inadequate.
- The tree view is too complicated. It needs less stuff displayed by
default, and probably more highlighting to indicate what part is
currently running.
- The solvers have too many redundant steps.
- The "solve" and "more" buttons run 1,000 steps, but it turns out
sometimes that locks the entire GUI up for as much as 30 seconds. There
ought to be some kind of progress display, the work should be in a
separate thread to avoid stalling the GUI, and there ought to be an
abort button. Also, perhaps the process should be limited by wall-time
rather than number of steps. (Wall-time seems oddly variable.)
- There ought to be a way to put comments in source code files.
- It really irritates me that the load and save requesters default to My
Documents rather than the current folder. There must be some obscure
hack to fix that...
Whether I will fix these issues or move on to another project remains to
be seen. Originally my goal was to write the program in Java (which is
object-oriented), and then have a go at translating it to C++. (Without
the GUI, because I have no idea how to do GUI programming in C++, and it
sounds highly non-trivial.) But actually, it looks like it's going to be
impossible, because it fundamentally /requires/ abstract classes, which
are hard in C++. So probably another Java project then...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Am 07.06.2012 12:06, schrieb Invisible:
> Whether I will fix these issues or move on to another project remains to
> be seen. Originally my goal was to write the program in Java (which is
> object-oriented), and then have a go at translating it to C++. (Without
> the GUI, because I have no idea how to do GUI programming in C++, and it
> sounds highly non-trivial.) But actually, it looks like it's going to be
> impossible, because it fundamentally /requires/ abstract classes, which
> are hard in C++. So probably another Java project then...
Abstract classes hard in C++? That's news to me. Last time I checked
they were quite trivial:
class C
{
public:
virtual ~C() {}
virtual void DoSomething() = 0;
};
There. An abstract class.
class D: public C
{
public:
virtual ~D() {}
virtual void DoSomething() { ... }
};
There. A class implementing the abstract one.
C* Foo;
Foo = new D();
Foo.DoSomething();
delete Foo;
There. An implementation of an abstract class in action.
Did I miss anything?
If you're using MS Visual Studio (or any other sane contemporary C++
IDE), GUI programming is quite easy as well; after all, you have a GUI
builder included. (Writing a /portable/ GUI in C++ is an entirely
different matter of course, and the beginners' how-to boils down to one
and a half words: "Don't.")
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> Whether I will fix these issues or move on to another project remains to
>> be seen. Originally my goal was to write the program in Java (which is
>> object-oriented), and then have a go at translating it to C++. (Without
>> the GUI, because I have no idea how to do GUI programming in C++, and it
>> sounds highly non-trivial.) But actually, it looks like it's going to be
>> impossible, because it fundamentally /requires/ abstract classes, which
>> are hard in C++. So probably another Java project then...
>
> Abstract classes hard in C++? That's news to me. Last time I checked
> they were quite trivial
> Did I miss anything?
...or rather, to /use/ run-time polymorphism, you need to do manual
memory management, and manual memory management is infamously hard.
> If you're using MS Visual Studio (or any other sane contemporary C++
> IDE), GUI programming is quite easy as well; after all, you have a GUI
> builder included.
Yeah, but I'm told programming the Win32 APIs directly is incredibly
hard. Even if you've got an IDE to generate some of the code for you, I
rather suspect that without a deep understanding for how it works,
you'll never be able to fill in the empty bits where your application
goes...
> (Writing a /portable/ GUI in C++ is an entirely
> different matter of course, and the beginners' how-to boils down to one
> and a half words: "Don't.")
This is true of /most/ programming languages that compile to native
code, to be fair. ;-)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Am 07.06.2012 13:34, schrieb Invisible:
>>> Whether I will fix these issues or move on to another project remains to
>>> be seen. Originally my goal was to write the program in Java (which is
>>> object-oriented), and then have a go at translating it to C++. (Without
>>> the GUI, because I have no idea how to do GUI programming in C++, and it
>>> sounds highly non-trivial.) But actually, it looks like it's going to be
>>> impossible, because it fundamentally /requires/ abstract classes, which
>>> are hard in C++. So probably another Java project then...
>>
>> Abstract classes hard in C++? That's news to me. Last time I checked
>> they were quite trivial
>
>> Did I miss anything?
>
> ...or rather, to /use/ run-time polymorphism, you need to do manual
> memory management, and manual memory management is infamously hard.
... or use Boost's (or C++11's) smart pointers.
>> If you're using MS Visual Studio (or any other sane contemporary C++
>> IDE), GUI programming is quite easy as well; after all, you have a GUI
>> builder included.
>
> Yeah, but I'm told programming the Win32 APIs directly is incredibly
> hard. Even if you've got an IDE to generate some of the code for you, I
> rather suspect that without a deep understanding for how it works,
> you'll never be able to fill in the empty bits where your application
> goes...
Sane IDEs don't use the Win32 C API for GUI (or for most anything else
for that matter); instead, they come with a fancy object-oriented
framework of libraries hiding all the uglies from you. (MFC used to be
the thing for MS Visual C++; they have something new by now, same thing
they use for C#.)
>> (Writing a /portable/ GUI in C++ is an entirely
>> different matter of course, and the beginners' how-to boils down to one
>> and a half words: "Don't.")
>
> This is true of /most/ programming languages that compile to native
> code, to be fair. ;-)
True enough.
First time I ever wrote a C program that needed graphical output, I
actually opted for using a printer rather than the computer display,
because I already knew some PostScript :-P (Later I employed GhostScript
of course; but only for test runs, as the "display" quality of the A3
printer was unparalleled :-))
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> ...or rather, to /use/ run-time polymorphism, you need to do manual
>> memory management, and manual memory management is infamously hard.
>
> ... or use Boost's (or C++11's) smart pointers.
Wouldn't that mean I'd have to somehow install Boost and tell the IDE
where the hell to find it?
Compared to that, manual memory management sounds trivial. :-P
>>> If you're using MS Visual Studio (or any other sane contemporary C++
>>> IDE), GUI programming is quite easy as well; after all, you have a GUI
>>> builder included.
>>
>> Yeah, but I'm told programming the Win32 APIs directly is incredibly
>> hard.
>
> Sane IDEs don't use the Win32 C API for GUI (or for most anything else
> for that matter); instead, they come with a fancy object-oriented
> framework of libraries hiding all the uglies from you. (MFC used to be
> the thing for MS Visual C++; they have something new by now, same thing
> they use for C#.)
Interesting. Is /that/ why I keep having to install the "VisualStudio
C++ runtime" every few weeks?
> First time I ever wrote a C program that needed graphical output, I
> actually opted for using a printer rather than the computer display,
> because I already knew some PostScript :-P (Later I employed GhostScript
> of course; but only for test runs, as the "display" quality of the A3
> printer was unparalleled :-))
Oh, that's old skool! :-D
I'm told back in the days of the old mainframes, /all/ user output was
through a printer. It literally didn't /have/ a video display /at all/.
So the PRINT command in BASIC? It used to actually *print* stuff! :-D
Suddenly using HTML and HTTP to present a GUI doesn't seem quite so
insane after all...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 07/06/2012 1:12 PM, Invisible wrote:
> I'm told back in the days of the old mainframes, /all/ user output was
> through a printer. It literally didn't /have/ a video display /at all/.
> So the PRINT command in BASIC? It used to actually *print* stuff! :-D
I remember playing "golf" where the graphical display was a printer.
--
Regards
Stephen
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Invisible <voi### [at] dev null> wrote:
> >> ...or rather, to /use/ run-time polymorphism, you need to do manual
> >> memory management, and manual memory management is infamously hard.
> >
> > ... or use Boost's (or C++11's) smart pointers.
> Wouldn't that mean I'd have to somehow install Boost and tell the IDE
> where the hell to find it?
> Compared to that, manual memory management sounds trivial. :-P
Just use a compiler that support C++11. You can then use std::shared_ptr
to manage the objects. (If the object doesn't need to be shared, only moved
around, then you can use std::unique_ptr instead, which is more efficient.)
To be fair, though, if your program allocates and deallocates such objects
in large quantities very fast, the Java version will probably be faster than
the C++ version (because memory allocation has been optimized in Java but
not in C++).
(To be clear: It's not the polymorphism that's slow in C++. It's all the
new's and delete's.)
Some applications require runtime polymorphism of objects (GUI programming
being the most prominent example), but in many cases compile-time
polymorphism using templates is enough (and significantly more efficient).
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Am 07.06.2012 14:12, schrieb Invisible:
>>> ...or rather, to /use/ run-time polymorphism, you need to do manual
>>> memory management, and manual memory management is infamously hard.
>>
>> ... or use Boost's (or C++11's) smart pointers.
>
> Wouldn't that mean I'd have to somehow install Boost and tell the IDE
> where the hell to find it?
As for the smart pointers, actually no - the smart pointers magic is all
header files, so you just need to copy those to a suitable subdirectory
of your own project and add that directory to the list of preprocessor
include directories.
And if you use VS 2010 (or later), it's even as simple as activating the
C++11 (aka "C++0x") features. The C++11 smart pointers are actually
identical to the boost smart pointers, except that they live in a
different namespace.
The only caveat not explicitly warned about in the smart pointers
documentation is that the smart pointer assignment operator ("=") is
implemented as a swap operation, so to create another smart pointer
referencing the same object you need to explicitly make use of the smart
pointers' copy constructor:
typedef shared_ptr<FooType> FooPtr; // really helps
FooPtr A(new FooType());
FooPtr B;
B = FooPtr(A); // NOT just "B = A;"
or just
FooPtr B(A);
shared_ptr is complemented with weak_ptr.
>> Sane IDEs don't use the Win32 C API for GUI (or for most anything else
>> for that matter); instead, they come with a fancy object-oriented
>> framework of libraries hiding all the uglies from you. (MFC used to be
>> the thing for MS Visual C++; they have something new by now, same thing
>> they use for C#.)
>
> Interesting. Is /that/ why I keep having to install the "VisualStudio
> C++ runtime" every few weeks?
Not really. That's just the /general/ habit of dynamically-linked
software. Usually the VS C++ Runtime should simply discover that the VS
C++ Runtime is already installed though.
> I'm told back in the days of the old mainframes, /all/ user output was
> through a printer. It literally didn't /have/ a video display /at all/.
> So the PRINT command in BASIC? It used to actually *print* stuff! :-D
Yup. Heard that, too. Haven't ever seen any proof with my own eyes
though, so it must be urban legend :-P
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
clipka <ano### [at] anonymous org> wrote:
> The only caveat not explicitly warned about in the smart pointers
> documentation is that the smart pointer assignment operator ("=") is
> implemented as a swap operation, so to create another smart pointer
> referencing the same object you need to explicitly make use of the smart
> pointers' copy constructor:
That makes no sense. It would break basically everything if it were like
that.
You are confusing it with how operator= of some versions of shared_ptr might
be implemented, in that it internally swaps its contents with a temporary
that has been initialized with the parameter (this is done to avoid problems
that would happen when assigning to itself). Externally there's no swapping
behavior (and there can't be).
--
- Warp
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> I'm told back in the days of the old mainframes, /all/ user output was
>> through a printer. It literally didn't /have/ a video display /at all/.
>> So the PRINT command in BASIC? It used to actually *print* stuff! :-D
>
> Yup. Heard that, too. Haven't ever seen any proof with my own eyes
> though, so it must be urban legend :-P
I've personally operated a green-screen terminal where there's a
2-second delay between pressing a key and seeing the character on the
screen because it's a dumb terminal connected over a modem link to a
mainframe somewhere. After keying in several /very/ cryptic commands,
the line printer next to be sprang into life. And let me tell you, those
things are LOUD! I was using it to print benefits cheques for the local
county council, in around about 1997 or so. I doubt that their
infrastructure has been modernised since then...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Am 07.06.2012 16:35, schrieb Warp:
> clipka<ano### [at] anonymous org> wrote:
>> The only caveat not explicitly warned about in the smart pointers
>> documentation is that the smart pointer assignment operator ("=") is
>> implemented as a swap operation, so to create another smart pointer
>> referencing the same object you need to explicitly make use of the smart
>> pointers' copy constructor:
>
> That makes no sense. It would break basically everything if it were like
> that.
That's what I thought when I first saw it (or, rather, imagined to see it).
> You are confusing it with how operator= of some versions of shared_ptr might
> be implemented, in that it internally swaps its contents with a temporary
> that has been initialized with the parameter (this is done to avoid problems
> that would happen when assigning to itself). Externally there's no swapping
> behavior (and there can't be).
Hm... I just re-read the boost shared_ptr assignment specs, and you're
obviously right. How I read that misconception into the docs I have no
idea (it's been unchanged for ages), but for obvious reasons it stuck.
I guess I'm just having a bit of cleanup work in the POV-Ray code cut
out for me...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 07/06/2012 11:06 AM, Invisible wrote:
> Building the GUI was a somewhat frustrating exercise. The UI painter
> makes it easy enough to draw what you want. Except that the UI painter
> uses the "Windows" look and feel, while the generated code defaults to
> the "Nimbus" look and feel, and AFAIK there is /no way/ to change this.
I forgot to even mention: By default, nothing is resizable. As in, when
you resize the window, the bottom-most pane inherits all the additional
space. And there's no way to make the other regions larger.
To fix this, you have to use a "splitter". And the way it works is
pretty retarded. (In particular, you cannot have, say, a 3-way split.
You can only have nested 2-way splits. Presumably because that made the
library author's job easier. :-P ) It took me ages to get it to actually
work right!
And I still don't know why the text field at the top insists it should
have space for /4 lines/ of text, even if you haven't typed that much
text in. It's very irritating...
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Le 2012-06-07 11:35, Invisible a écrit :
>>> I'm told back in the days of the old mainframes, /all/ user output was
>>> through a printer. It literally didn't /have/ a video display /at all/.
>>> So the PRINT command in BASIC? It used to actually *print* stuff! :-D
>>
>> Yup. Heard that, too. Haven't ever seen any proof with my own eyes
>> though, so it must be urban legend :-P
>
> I've personally operated a green-screen terminal where there's a
> 2-second delay between pressing a key and seeing the character on the
> screen because it's a dumb terminal connected over a modem link to a
> mainframe somewhere. After keying in several /very/ cryptic commands,
> the line printer next to be sprang into life. And let me tell you, those
> things are LOUD! I was using it to print benefits cheques for the local
> county council, in around about 1997 or so. I doubt that their
> infrastructure has been modernised since then...
Even most dumb terminal had local screen management. That's why on most
of them you had separate RETURN and ENTER keys. RETURN would simply
move the cursor down one line, and ENTER would transmit the entire page
(or all the filled-in filed, depending on your terminal).
Yes, hitting ENTER on a partially filled-in screen would display the
behaviour you saw, since the host end would simply tell you "hey, you
didn't finish filling this screen!"
--
/*Francois Labreque*/#local a=x+y;#local b=x+a;#local c=a+b;#macro P(F//
/* flabreque */L)polygon{5,F,F+z,L+z,L,F pigment{rgb 9}}#end union
/* @ */{P(0,a)P(a,b)P(b,c)P(2*a,2*b)P(2*b,b+c)P(b+c,<2,3>)
/* gmail.com */}camera{orthographic location<6,1.25,-6>look_at a }
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
>> I've personally operated a green-screen terminal where there's a
>> 2-second delay between pressing a key and seeing the character on the
>> screen because it's a dumb terminal connected over a modem link to a
>> mainframe somewhere. After keying in several /very/ cryptic commands,
>> the line printer next to be sprang into life. And let me tell you, those
>> things are LOUD! I was using it to print benefits cheques for the local
>> county council, in around about 1997 or so. I doubt that their
>> infrastructure has been modernised since then...
>
> Even most dumb terminal had local screen management. That's why on most
> of them you had separate RETURN and ENTER keys. RETURN would simply move
> the cursor down one line, and ENTER would transmit the entire page (or
> all the filled-in filed, depending on your terminal).
>
> Yes, hitting ENTER on a partially filled-in screen would display the
> behaviour you saw, since the host end would simply tell you "hey, you
> didn't finish filling this screen!"
This one didn't appear to work that way. The characters literally didn't
appear until a second or so after you typed them. (I have no idea what
it was actually running on, but I assume some kind of modem...)
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|
 |