POV-Ray : Newsgroups : povray.off-topic : A tale of two cities Server Time
12 Oct 2026 09:31:21 EDT (-0400)
  A tale of two cities (Message 1 to 50 of 105)  
Goto Latest 50 Messages Next 50 Messages >>>
From: Invisible
Subject: A tale of two cities
Date: 13 Mar 2012 06:11:41
Message: <4f5f1d5d$1@news.povray.org>
Or rather, a tale of two IDEs for two programming languages.

Yesterday I downloaded and installed Visual C++ 2010 Express. (Can you 
guess which language that's for?) The installation takes /forever/. It's 
one of those programs where you "download the installer" and get a 20KB 
file that just runs the downloader for the /real/ installation program. 
(Why the **** do people do that?!) Still, at least once it's installed, 
it runs fairly fast.

In common with all known IDEs, hitting the "new project" button creates 
a project with /way/ more useless boilerplate code than you will ever 
need. I mean, it creates about half a dozen source files - two separate 
C++ files, three header files, etc. Which is completely overkill just 
for implementing Hello World. (It also sets the tab depth to something 
like 18 spaces or something equally absurd.)

My C++ is very rusty. Hell, I wasn't even that good in the first place! 
But deleting all the unwanted files and starting again from scratch, I 
was able to implement Hello World from memory without needing to look 
anything up. So that's a good start.

Now for my next trick, a Huffman encoder. In most languages it's 
trivially easy to implement, and yet it uses a surprising amount of 
language features. And, uh, yeah... I can't implement this. It's the 
damnedest thing, I swear I already wrote this code once... but I can't 
find it anywhere, so maybe I'm imagining it.

Anyway, C++ employs a manual memory management model. Surprisingly, if 
you can get away with using only STL containers, you don't have to know 
or care that this is the case. All that template magic neatly takes care 
of the problem for you. And that's great.

I made all the usual beginner's stupid mistakes - e.g., passing data 
structures by value, and then wondering why my alterations aren't 
visible from outside the function. (Most OO languages default to passing 
by reference. But then, most OO languages provide automatic memory 
management too...)

The real sticking point was when I started trying to use abstract 
classes. It seems that you cannot have a variable of an abstract class. 
(Because creating that variable would require creating an instance of an 
abstract class, which is illegal.) You can only have a variable that 
/points to/ such a value. (Because then what it points to can actually 
be some concrete subclass.)

That's all fine and logical and everything, but there's a nasty snag: 
Now you have to care about memory management. And there's no way around it.

I was eventually able to get the program to produce the correct output. 
However, it uses the dreaded "new" operator. In particular, it does 
/not/ use the "delete" operator anywhere. In other words, it leaks. I 
have literally no idea how to fix this. I can't think of any way of 
doing it that won't result in double-freeing objects. That's mainly 
because I can't put responsibility for object creation (and hence object 
destruction) in the logical place. And /that/ is because I don't have 
some of the necessary technical understanding.

I found a reasonable C++ introduction at cplusplus.com, but it doesn't 
explain several technical points which I'm unclear on. Does anybody know 
of a better resource? (Obviously, a Google search will turn up millions 
of results. It's hard to know which ones are /good/ resources, however.)



Having spent a few hours on that, I decided to turn my attention to 
Java. Now I've coded fairly extensively in Java in the past, but that 
was about 10 years ago. (Jesus Christ I'm old now! >_< ) I still 
remember most of the syntax, but I haven't actually tried to /compile/ 
any code for a very long time. I'm not sure if I'll remember how...

So I downloaded the NetBeans IDE for Java SE. Which immediately told me 
that I have to install the Java SE JDK before running the installer. 
Gee, thanks for that. :-P You couldn't have made that clearer from the 
download page, no?

So, 80MB for NetBeans, another 80MB for the JDK itself, and finally I'm 
in business. Now, I'm not saying NetBeans is /inefficient/, but 
swallowing 200MB of RAM just because I double-clicked the icon to open 
the IDE does seem /just a tad excessive/ to me. Initially I was just 
trying to figure out how to work the thing, but as I started to learn my 
way around and started trying to actually /do/ stuff, the IDE seemed 
unacceptably unresponsive. (Quite apart from visually /looking/ like 
something baked by an open source committee rather than being a polished 
commercial product.)

Like VS, asking NetBeans for a basic project generates a plateful of 
useless code that you then have to waste time deleting. (Apparently 
there's an Ant script somewhere too... whatever the hell that is.) It 
also sets the tab depth far, far too deep. But unlike VS, it also seems 
to /insist/ on incorrectly putting the open bracket on the same line as 
the declaration it begins. (This incorrect practise is also common in 
C++, and yet I didn't seem to have this problem with VS.) It's easy 
enough to manually fix, I suppose.

While VS does syntax highlighting and occasionally pops up a list of 
method names or something (usually a few seconds too late to be useful, 
or using out of date type information), NetBeans seems a little more 
impressive. Oh, it still does syntax highlighting. (With some rather 
unhelpful colour choices.) And it still pops up out-of-date method lists 
that actually get in the way far more than they help. But it goes a few 
steps further.

For example, Java is such a retarded language that the only way to copy 
some stuff from one array to another is to manually write a loop. So I 
wrote a loop. And a little box popped up saying "manual array copy 
detected - replace with System.arraycopy()?" I clicked the button. All 
the temporary variables vanished, and were replaced with the above 
method call, with the correct source and destination, and even the 
correct array indices. I'm impressed.

Or rather, I'm impressed at the IDE. Implementing array copying as a 
static method on a general utility class? Yeah, /that/ sounds like 
fantastic OO library design! :-P Really, Java? I mean, really? Still, at 
least you don't need to use an abstract factory factory to use it. The 
syntax is quite straight forward.

Also interesting is that when you call a method, it seems to take a 
guess at what variables currently in scope are of the correct type, and 
fills that in for you automatically. Handy when it works, mildly 
irritating when it doesn't.

Needless to say, Hello World was no challenge at all. Implementing my 
Huffman encoder was a little more tricky. When I ran it, I got a null 
pointer exception. Amusingly [or not], it is apparently impossible to 
make the IDE halt the program at the location where the exception is 
thrown. Even in debug mode, it just runs the program, prints out the 
exception, and then quits. No way of, you know, inspecting the program 
state at the moment of the exception to actually see what the problem 
is, or anything like that. In fact, come to mention it, I can't find any 
way at all to single-step through the program. VS did all of this and 
more. :-P

As always with these types of problems, I eventually discovered that I'd 
forgotten to initialise something in the code. (An empty array is of 
course /not/ the same thing as a null pointer...) Once I fixed that, it 
all worked just fine. If I had had access to a debugger that would 
actually tell me which field it was that was uninitialised, it would 
have taken seconds to figure out the problem and fix it. It only took 
half an hour because I had to sprinkle print() all over the place until 
the problem became apparent.

So there we are. I doubt I'd remember much about the AWT (although, 
didn't they deprecate that in favour of Swing?), but I can certainly 
still write algorithmic code in Java without much ado. Maybe today I'll 
try something more ambitious with it. If I can avoid throwing the IDE 
out of a window.

(Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have 
to do with networking? The "beans" part I kinda get; everything 
Java-related has to be themed on coffee or coffee beans. But why "net"?)


Post a reply to this message

From: John VanSickle
Subject: Re: A tale of two cities
Date: 13 Mar 2012 07:33:47
Message: <4f5f309b$1@news.povray.org>
On 3/13/2012 6:11 AM, Invisible wrote:

> I was eventually able to get the program to produce the correct output.
> However, it uses the dreaded "new" operator. In particular, it does
> /not/ use the "delete" operator anywhere. In other words, it leaks. I
> have literally no idea how to fix this. I can't think of any way of
> doing it that won't result in double-freeing objects. That's mainly
> because I can't put responsibility for object creation (and hence object
> destruction) in the logical place. And /that/ is because I don't have
> some of the necessary technical understanding.
>
> I found a reasonable C++ introduction at cplusplus.com, but it doesn't
> explain several technical points which I'm unclear on. Does anybody know
> of a better resource? (Obviously, a Google search will turn up millions
> of results. It's hard to know which ones are /good/ resources, however.)

Good memory management in C and C++ are things you really have to learn 
as you go along.  You can probably encapsulate your heap object pointers 
into a handler class, but you probably have some learning to go before 
you're ready to implement that.

I think the best way to go is to decide whether a given pointer 
represents an object that is created on the heap and is owned by the 
pointer's container, or if it just refers to an object that is owned by 
some other container.  The owner takes care of deleting its objects 
created on the heap, but otherwise objects get left alone.

> (Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have
> to do with networking? The "beans" part I kinda get; everything
> Java-related has to be themed on coffee or coffee beans. But why "net"?)

Apparently Java's developers are focused on its Web capabilities, and 
are trying to emphasize that.

Regards,
John


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:03:31
Message: <4f5f61c3$1@news.povray.org>
On 13/03/2012 11:33 AM, John VanSickle wrote:
> On 3/13/2012 6:11 AM, Invisible wrote:
>
>> I was eventually able to get the program to produce the correct output.
>> However, it uses the dreaded "new" operator. In particular, it does
>> /not/ use the "delete" operator anywhere. In other words, it leaks.
>
> Good memory management in C and C++ are things you really have to learn
> as you go along. You can probably encapsulate your heap object pointers
> into a handler class, but you probably have some learning to go before
> you're ready to implement that.
>
> I think the best way to go is to decide whether a given pointer
> represents an object that is created on the heap and is owned by the
> pointer's container, or if it just refers to an object that is owned by
> some other container. The owner takes care of deleting its objects
> created on the heap, but otherwise objects get left alone.

Sure. I get all that. The problems I'm facing are technical, not 
theoretical. I know what code I want to write, but I don't know how to 
use the language features to write that code.

>> (Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have
>> to do with networking? The "beans" part I kinda get; everything
>> Java-related has to be themed on coffee or coffee beans. But why "net"?)
>
> Apparently Java's developers are focused on its Web capabilities, and
> are trying to emphasize that.

By sticking "net" in the name? Heh, that's like inventing a scripting 
language and naming it after Java to try and latch onto its 
popularity... Oh, wait. Somebody did that. :-P


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:15:57
Message: <4f5f64ad$1@news.povray.org>
On 13/03/2012 10:11 AM, Invisible wrote:
> So, 80MB for NetBeans, another 80MB for the JDK itself, and finally I'm
> in business. Now, I'm not saying NetBeans is /inefficient/, but
> swallowing 200MB of RAM just because I double-clicked the icon to open
> the IDE does seem /just a tad excessive/ to me. Initially I was just
> trying to figure out how to work the thing, but as I started to learn my
> way around and started trying to actually /do/ stuff, the IDE seemed
> unacceptably unresponsive. (Quite apart from visually /looking/ like
> something baked by an open source committee rather than being a polished
> commercial product.)

I eventually gave up with NetBeans. It's just too cripplingly slow. (I 
did not have this problem with VS.) If I type something and have to wait 
/4 seconds/ for anything to appear on the screen, that's too slow, IMHO.

Seriously. Once I got to a handful of files, amounting to a grand total 
of 6KB of Java source, performance became unacceptably poor. I also love 
the way that running the program randomly fails from time to time. You 
click "run", and it says "build successful", followed by "cannot find 
compiled code". But if you click the button enough times, eventually it 
runs perfectly. So... WTF is wrong with it?!

In all, I was spending /far/ too much time fighting the IDE and not 
enough time actually coding stuff. So I switched back to a text editor 
and a command prompt. (Amusing how installing the JDK doesn't add any of 
the Java binaries to the search path. If by "amusing" you mean "tedious 
and annoying"...)

Some of you may remember that logic simulator I built in Haskell a while 
back. If I recall, I challenged Warp to implement it in C++, and he 
couldn't even figure out how the heck it works. (I must admit, it's a 
loopy piece of coding.) Perhaps a Java implementation will be less 
mind-bending for any curious souls - or perhaps not, IDK. Either way, 
it'll be a while before *I* can implement it in C++. (!)

Also, I think I might have to build a parser for Java. Because, damnit, 
writing stuff like

   new Or(new And(new Equals(new NameVar("x"), new IntegerConst(1)), new 
Equals(new NameVar("y"), new IntegerConst(2))), ...

becomes tedious /rapidly/!

I keep hearing that Java has added generics since I last worked with it. 
I find it amusing that we can now write HashMap<Foo, Bar>, and yet we 
have type signatures like

   public Object get(Object key);

Really? I mean, really? Should that not be

   public V get(K key);

or similar? Is that not the entire /point/ of generics?

Then we have fun such as Object.clone(), which is [still] defined to 
return Object. So you get to write stuff like

   java.util.HashMap<Variable, Expression> copy = 
(java.util.MashMap<Variable, Expression>) old.clone();

And of course, no way to define type aliases (and no automatic type 
inference either), so if I decide to change the HashMap for, I don't 
know, a TreeMap perhaps, I'm going to have to change type signatures in 
a dozen places. Gee, thanks for that. :-P

Even more fun, apparently writing the above code is an "unsafe, 
unchecked construct" - or so the compiler warns me with /every single 
damned compile/. Despite the fact that the above is statically 
guaranteed to always work. *sigh*

Yes, Java /still/ sucks. :-P


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:46:11
Message: <4f5f6bc3$1@news.povray.org>
On 13/03/2012 03:15 PM, Invisible wrote:
> I keep hearing that Java has added generics since I last worked with it.
> I find it amusing that we can now write HashMap<Foo, Bar>, and yet we
> have type signatures like
>
> public Object get(Object key);
>
> Really? I mean, really? Should that not be
>
> public V get(K key);
>
> or similar? Is that not the entire /point/ of generics?

Interesting fact: It seems the latest JDK implements /two/ versions of 
the same interface.

public interface Iterator
{
   public boolean hasNext();
   public Object next();
   public void remove();
}

public interface Iterator<E>
{
   public boolean hasNext();
   public E next();
   public void remove();
}

If you accidentally forget to mention the element type, you get the old 
version of the interface, with all its type unsafety. Isn't that great? 
*sigh*


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 11:56:43
Message: <4f5f6e3a@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> In common with all known IDEs, hitting the "new project" button creates 
> a project with /way/ more useless boilerplate code than you will ever 
> need.

  Probably because you created a new *Windows* project, rather than a
portabla command-line one.

> The real sticking point was when I started trying to use abstract 
> classes. It seems that you cannot have a variable of an abstract class. 
> (Because creating that variable would require creating an instance of an 
> abstract class, which is illegal.) You can only have a variable that 
> /points to/ such a value. (Because then what it points to can actually 
> be some concrete subclass.)

  Dynamic binding, abstract classes, and even inheritance, are needed
in practice significantly less often than one might think (especially
if one comes from a background where that's basically the only way of
doing anything).

  In quite many cases it's enough to have classes with no dynamic binding
nor inheritance, and which are handled by value (at least if they contain
only moderate amount of data). In the case of a huffman coder, I really
don't understand what do you need abstract classes for. (There *is* such
a thing as over-designing, when talking about OOP.)

  In many cases if you design your program such that you don't need
dynamic binding, your program will often become more efficient in terms
of both speed and memory usage. (Not because dynamic binding would be
inefficient, as it isn't, but because dynamic memory allocation is, and
if we are talking about abstract classes, then dynamic memory allocation
usually goes hand in hand with it.)

  (Inheritance in itsef is not bad in this sense, because C++ does not
force dynamic binding. Base classes can sometimes be used to group common
implementations into a single module, to avoid code repetition. Using an
inherited class is in no way less efficient than one that has no parent
class at all. However, as said, even inheritance is less often necessary
in practice than one might think.)

> I was eventually able to get the program to produce the correct output. 
> However, it uses the dreaded "new" operator. In particular, it does 
> /not/ use the "delete" operator anywhere. In other words, it leaks. I 
> have literally no idea how to fix this. I can't think of any way of 
> doing it that won't result in double-freeing objects. That's mainly 
> because I can't put responsibility for object creation (and hence object 
> destruction) in the logical place. And /that/ is because I don't have 
> some of the necessary technical understanding.

  If you are an experienced, competent c++ programmer, each time you have
to write the dreaded keyword 'new', it should give you a feeling of unease,
and the instinctive desire to think of better alternatives. This even if
you have no problems whatsoever with memory management in this situation
(eg. because you are using a smart pointer). That's because 'new' is not
only a source of leaks, but also it's inefficient.

  There are, of course, situations where 'new' is the only and best
solution. For example, if you are implementing your own dynamic array
(which has something that std::vector does not provide), then there's
no problem. However, the usage of 'new' should in this case be tightly
restricted to happen inside this dynamic array class, strictly controlled
by it. Maximum encapsulation of the memory management is the key.

  If, for some strange reason, you need to allocate individual objects
dynamically with 'new', then you should either use a smart pointer to
handle it (C++11 provides std::unique_ptr and std::shared_ptr for this
purpose), or you should write a class that acts as such (in other words,
which acts kind of like a data container containing one element: The
allocated object.)

  Writing 'new' outside of a class member function (of a class that handles
that allocated memory, of course) is always a risk. Even if you make sure
there's a corresponding 'delete' at the end of the function, your code
will not be exception-safe (because if an exception happens before that
'delete', the allocated object will be leaked; the exception is if you
use a smart pointer such as std::unique_ptr to handle it).

  In practice I don't remember having to write 'new' even once outside
of a class that handles the allocated memory. Smart pointers are fine
and all, but they are seldom needed in practice.

  Now, writing a class that properly manages its dynamically allocated
memory is a non-trivial task of its own.

-- 
                                                          - Warp


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 13 Mar 2012 12:32:04
Message: <4f5f7684$1@news.povray.org>
On 13/03/2012 03:56 PM, Warp wrote:
> Invisible<voi### [at] devnull>  wrote:
>> In common with all known IDEs, hitting the "new project" button creates
>> a project with /way/ more useless boilerplate code than you will ever
>> need.
>
>    Probably because you created a new *Windows* project, rather than a
> portabla command-line one.

Nope. I specifically requested "console application".

>    Dynamic binding, abstract classes, and even inheritance, are needed
> in practice significantly less often than one might think (especially
> if one comes from a background where that's basically the only way of
> doing anything).

Perhaps. Although in a sense, I'm not actually "interested" in building 
a specific application here, I'm interested in figuring out how 
inheritance and so forth actually works in C++.

> In the case of a huffman coder, I really
> don't understand what do you need abstract classes for. (There *is* such
> a thing as over-designing, when talking about OOP.)

The most obvious way to implement this is to physically build a binary 
tree. That requires either inheritance, or else doing something sly with 
unions. (Or even being /really/ dirty and just having one node type, and 
ignoring the unused fields.)

Now for the /encoding/ part itself, I don't actually need a physical 
tree. I have a vague recollection that last time I did this, I ended up 
cheating and just storing a vector of codewords, and manually munging 
that. It's a lot less elegant, but avoids dynamic allocation. (Or 
rather, no it doesn't, but it hides it in STL containers, so you don't 
have to do it manually.)

This application is just supposed to be the "warm up" for my next 
project, which will involve building complex expression trees. I really 
don't see how you can get away with no dynamic binding when each node 
type needs to be processed differently. Unless you go all non-OO and try 
to implement node type dispatch manually...

>    In many cases if you design your program such that you don't need
> dynamic binding, your program will often become more efficient in terms
> of both speed and memory usage.

I guess to some extent it depends on whether your goals are efficiency 
or maintainability. Certainly the code I'm trying to write will probably 
take milliseconds to execute, whichever way I implement it. If I was 
writing something high-performance, I might care about such things.

>    If you are an experienced, competent c++ programmer, each time you have
> to write the dreaded keyword 'new', it should give you a feeling of unease,
> and the instinctive desire to think of better alternatives.

Well, I did try to think of a way around it. But I failed to come up 
with a solution.

>    There are, of course, situations where 'new' is the only and best
> solution. For example, if you are implementing your own dynamic array
> (which has something that std::vector does not provide), then there's
> no problem. However, the usage of 'new' should in this case be tightly
> restricted to happen inside this dynamic array class, strictly controlled
> by it. Maximum encapsulation of the memory management is the key.

The problem is, I want to copy some data, but since I don't know what 
class it belongs to, I have no idea how big it will be. Presumably 
there's some way around that, but damned if I know what it is... Like I 
say, I need to find a more thorough reading resource that explains this 
stuff properly.

>    Now, writing a class that properly manages its dynamically allocated
> memory is a non-trivial task of its own.

Is that not just a case of allocating the memory correctly in the 
constructor, and freeing it properly in the destructor? (I mean, 
assuming nobody tries to copy the object or free its dynamic memory or 
anything like that...)


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 13:20:55
Message: <4f5f81f5@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> > In the case of a huffman coder, I really
> > don't understand what do you need abstract classes for. (There *is* such
> > a thing as over-designing, when talking about OOP.)

> The most obvious way to implement this is to physically build a binary 
> tree. That requires either inheritance, or else doing something sly with 
> unions. (Or even being /really/ dirty and just having one node type, and 
> ignoring the unused fields.)

  I don't see why you need different types of objects for such a binary
tree. Each object can be identical to each other in structure. (If in
some nodes some of the fields are unused, so what? It will still be
significantly more efficient than dynamic binding.)

  You don't need to mess with unions unless you really, really need to
make the objects as small as physically possible. However, making them
that small is completely moot if you are going to allocate them
individually anyways (the allocation bookkeeping overhead will nullify
any space saving you could get from shaving off a few bytes using unions.)
It would only make a significant difference if you used arrays of
objects as your tree data structure, rather than allocating objects
individually, and there were tons and tons of elements.

> Now for the /encoding/ part itself, I don't actually need a physical 
> tree. I have a vague recollection that last time I did this, I ended up 
> cheating and just storing a vector of codewords, and manually munging 
> that. It's a lot less elegant, but avoids dynamic allocation. (Or 
> rather, no it doesn't, but it hides it in STL containers, so you don't 
> have to do it manually.)

  Using an array of objects (rather than individually allocated objects)
doesn't completely avoid memory allocation, but it minimizes their amount,
which is often very significant. (In other words, if your program makes
20 allocations instead of a million, it will have a significant impact
on the speed of the program.)

> This application is just supposed to be the "warm up" for my next 
> project, which will involve building complex expression trees. I really 
> don't see how you can get away with no dynamic binding when each node 
> type needs to be processed differently. Unless you go all non-OO and try 
> to implement node type dispatch manually...

  If you really must have nodes of differing types, then it will become
complicated from the point of view of memory management. Lack of garbage
collection can be a b**** sometimes. (Not that it's impossible; it just
requires a lot of care and strict coding practices to get it right. This
is something you usually want to avoid altogether, if possible.)

  Of course your nodes could simply be (smart) pointers of a base class
type, but then you will be making twice as many allocations (because for
each node you will be allocating the node itself, which is a smart pointer,
*and* the object that the node is pointing to), which is even worse from
an efficiency point of view. It becomes simpler like this, but don't expect
extreme speed. (Haskell probably would beat C++ in this situation.)

  It's sometimes quite a bummer, but when writing efficient C++ you have
to always think "how many memory allocations will this perform?" (even,
and especially, when using STL data containers). The less individual
memory allocations are done, the better. (But of course that's not the
only thing that affects speed, but it's the one major thing not related
to the algorithm itself that does.)

  I have to grant that languages like Java are better at this because
there you don't have to worry about how many allocations are performed
(as JVM's have a significantly faster memory allocation than the C/C++
runtime.)

> >    In many cases if you design your program such that you don't need
> > dynamic binding, your program will often become more efficient in terms
> > of both speed and memory usage.

> I guess to some extent it depends on whether your goals are efficiency 
> or maintainability.

  Avoiding dynamic binding does not automatically mean that your program
becomes more complicated and harder to maintain. In fact, it can sometimes
mean the opposite. Sometimes your programs actually become *simpler* and
much easier to understand. Full OOP (beyond simple encapsulation using
classes) is not always the universal panacea for clarity and maintainability.
(Of course this depends on each individual case.)

> Certainly the code I'm trying to write will probably 
> take milliseconds to execute, whichever way I implement it. If I was 
> writing something high-performance, I might care about such things.

  But even then you have to think which design is easiest in terms of
memory management. The less you have to manage memory manually, the
better. Your program becomes safer and simpler.

> The problem is, I want to copy some data, but since I don't know what 
> class it belongs to, I have no idea how big it will be.

  I didn't understand your problem from that description alone.

> >    Now, writing a class that properly manages its dynamically allocated
> > memory is a non-trivial task of its own.

> Is that not just a case of allocating the memory correctly in the 
> constructor, and freeing it properly in the destructor? (I mean, 
> assuming nobody tries to copy the object or free its dynamic memory or 
> anything like that...)

  The simplest design is to delete the allocated memory in the destructor
(it doesn't really matter where inside the class the memory is allocated
as long as the pointer is kept as 0 when there's nothing allocated) and
then disabling the copy constructor and assignment operators. (In C++98
this is done by declaring them private and not implementing them. In C++11
you can explicitly express this with a keyword.)

  Often this is enough. However, sometimes you would want to be able
to copy and assign objects of that class type around. That's where the
non-triviality kicks in.

  The first problem is: How should the object be copied? There are many
possibilities:

- Perform a deep copy. Every time the object is copied or assigned, all
of the data it's managing is copied. This is the easiest way of managing
copying, but it can be pretty inefficient with large amounts of data (and
because each time you make a copy you need an additional 'new').

- Make the class act as a reference to the managed data, in which case each
copy *shares* the managed data. In this case you need to use reference
counting to know when to delete the data. You also have to design your
program taking into account that the object is acting as a reference to
the data, not as the data itself. (This can work pretty well if your
data object is considered immutable.)

- Perform lazy copying. In other words, copying/assigning the object does
not yet deep-copy the data. Only when the data is modified it will be
copied if it was being shared between more than one object. This makes
copying and assigning more efficient, but accessors less.

- The data is *moved* from the original to the copy. This is very efficient
(because you don't need reference counting or anything else) but can be
quite limiting (because you are not actually copying anything, just moving
the data from one object to another).

  The second problem is that implementing these is not completely trivial
and requires attention to detail and knowing the traps.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 13 Mar 2012 13:31:25
Message: <4f5f846c@news.povray.org>
Warp <war### [at] tagpovrayorg> wrote:
>   The first problem is: How should the object be copied? There are many
> possibilities:

  If you are wondering which solution the STL data containers use,
it's usually just a simple deep-copy whenever the container is copied
or assigned. (While this is implementation-defined, you can assume that
the vast majority, if not all, of the STL implementations out there use
deep copying.) You should take this into account when using the STL.
(In other words, never needlessly copy/assign a large data container.)

  As said, deep-copying is the easiest/simplest solution in terms of
memory management, but you have to be careful to not be copying them
around without a good reason.

-- 
                                                          - Warp


Post a reply to this message

From: nemesis
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:27:43
Message: <4f5f9faf$1@news.povray.org>
Invisible escreveu:
> On 13/03/2012 10:11 AM, Invisible wrote:
> I eventually gave up with NetBeans. It's just too cripplingly slow. (I 
> did not have this problem with VS.) If I type something and have to wait 
> /4 seconds/ for anything to appear on the screen, that's too slow, IMHO.

ah, children from the 90's...

> Seriously. Once I got to a handful of files, amounting to a grand total 
> of 6KB of Java source, performance became unacceptably poor.

That's not my (ackowledged little) experience.  And surely not of most 
people working on some hairy shared projects.

> In all, I was spending /far/ too much time fighting the IDE and not 
> enough time actually coding stuff.

cool, now you'll be just fighting a wholesomely stupid language.

*oh, I felt so Darrenish now*

> Some of you may remember that logic simulator I built in Haskell a while 
> back. If I recall, I challenged Warp to implement it in C++, and he 
> couldn't even figure out how the heck it works.

Perhaps you should have told him what the code is supposed to do rather 
than expect someone to figure out what some haskell code is doing.

Here's a challenge for you.  What do these haskell snippets are supposed 
to do?

snippet 1:

((.)$(.))

snippet 2:

f >>= a . b . c =<< g


and for a bonus, guess what this one does:

import System.Environment

foo n = 0 % (0 # (1,0,1)) where
  i%ds
   | i >= n = []
   | True = (concat h ++ "\t:" ++ show j ++ "\n") ++ j%t
   where k = i+10; j = min n k
         (h,t) | k > n = (take (n`mod`10) ds ++ replicate (k-n) " ",[])
               | True = splitAt 10 ds
  j # s | n>a || r+n>=d = k # t
      | True = show q : k # (n*10,(a-(q*d))*10,d)
   where k = j+1; t@(n,a,d)=k&s; (q,r)=(n*3+a)`divMod`d
  j&(n,a,d) = (n*j,(a+n*2)*y,d*y) where y=(j*2+1)

main = putStr.foo.read.head =<< getArgs


no googling, huh? ;)


> Yes, Java /still/ sucks. :-P

Yes and that is a feature by design.

What doesn't suck is the JVM and the tens of thousands of useful libs 
that run atop it.  It's the only truly cross-platform performant VM out 
there.  Think about it, libs you don't actually need to recompile on 
your machine.

And if you don't like java, you can just choose from many languages 
running atop it and leveraging from said libs:  Scala, Jython, JRuby, 
even quite a few Scheme implementations... any haskell work on this front?

BTW, Ant is yet another example of XML-madness:  it's basically a 
verbose XML makefile for java.

-- 
a game sig: http://tinyurl.com/d3rxz9


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:40:42
Message: <4f5fa2ba@news.povray.org>
On 13/03/2012 19:27, nemesis wrote:
> Invisible escreveu:
>> On 13/03/2012 10:11 AM, Invisible wrote:
>> I eventually gave up with NetBeans. It's just too cripplingly slow. (I
>> did not have this problem with VS.) If I type something and have to
>> wait /4 seconds/ for anything to appear on the screen, that's too
>> slow, IMHO.
>
> ah, children from the 90's...

I wish. :-P

Seriously. Visual Studio manages to be responsive enough, and not eat 
half my RAM. NetBeans can't. IMHO, that makes NetBeans inferior.

>> Seriously. Once I got to a handful of files, amounting to a grand
>> total of 6KB of Java source, performance became unacceptably poor.
>
> That's not my (ackowledged little) experience. And surely not of most
> people working on some hairy shared projects.

I can only say what I saw, not what other people see.

>> In all, I was spending /far/ too much time fighting the IDE and not
>> enough time actually coding stuff.
>
> cool, now you'll be just fighting a wholesomely stupid language.

That's the one. ;-)

>> Some of you may remember that logic simulator I built in Haskell a
>> while back. If I recall, I challenged Warp to implement it in C++, and
>> he couldn't even figure out how the heck it works.
>
> Perhaps you should have told him what the code is supposed to do rather
> than expect someone to figure out what some haskell code is doing.

Well, I did try to explain it in words, but sometimes source code is 
more exact.

> Here's a challenge for you. What do these haskell snippets are supposed
> to do?
>
> snippet 1:
>
> ((.)$(.))

ASCII art? ;-)

In fact, the "$" is necessary. Either way, this takes a 3-argument 
function, the first argument to the function, a function that transforms 
some type into the type of the second argument, and a suitable argument 
to transform. Or, in symbols,

(x -> y -> z) -> x -> (j -> y) -> y -> z

> snippet 2:
>
> f >>= a . b . c =<< g

Without knowing what the variables are bound to, this cannot be 
answered. It would be like saying "what does Foo(Bar(5)) do?"

> and for a bonus, guess what this one does:
>
> import System.Environment
>
> foo n = 0 % (0 # (1,0,1)) where
> i%ds
> | i >= n = []
> | True = (concat h ++ "\t:" ++ show j ++ "\n") ++ j%t
> where k = i+10; j = min n k
> (h,t) | k > n = (take (n`mod`10) ds ++ replicate (k-n) " ",[])
> | True = splitAt 10 ds
> j # s | n>a || r+n>=d = k # t
> | True = show q : k # (n*10,(a-(q*d))*10,d)
> where k = j+1; t@(n,a,d)=k&s; (q,r)=(n*3+a)`divMod`d
> j&(n,a,d) = (n*j,(a+n*2)*y,d*y) where y=(j*2+1)
>
> main = putStr.foo.read.head =<< getArgs

That's not even parsable. (Indentation is significant, remember?)

> no googling, huh? ;)

All I need is Hoogle. :-P

>> Yes, Java /still/ sucks. :-P
>
> Yes and that is a feature by design.

O RLY?

> What doesn't suck is the JVM and the tens of thousands of useful libs
> that run atop it. It's the only truly cross-platform performant VM out
> there. Think about it, libs you don't actually need to recompile on your
> machine.

Ha! If only... They don't say "write once, test everywhere" for nothing. ;-)

> And if you don't like java, you can just choose from many languages
> running atop it and leveraging from said libs: Scala, Jython, JRuby,
> even quite a few Scheme implementations... any haskell work on this front?

Darren claims they committed to a feature freeze too soon. I don't know 
about the low-level details of the JVM. But I gather that, say, adding 
Java generics required lots of ugly hacks so it didn't break compatibility.

I hear there are other languages that target the JVM. Presumably you 
still can't use any of the existing libraries though. (Not that any of 
them are much good.)

Oh, Haskell? Yeah, I gather a few people have tried to target the JVM 
with it. Nothing production-grade currently exists, however.

> BTW, Ant is yet another example of XML-madness: it's basically a verbose
> XML makefile for java.

Oh well. At least you don't need tab characters. :-P


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:41:30
Message: <4f5fa2ea$1@news.povray.org>
>> The most obvious way to implement this is to physically build a binary
>> tree. That requires either inheritance, or else doing something sly with
>> unions. (Or even being /really/ dirty and just having one node type, and
>> ignoring the unused fields.)
>
>    I don't see why you need different types of objects for such a binary
> tree. Each object can be identical to each other in structure. (If in
> some nodes some of the fields are unused, so what? It will still be
> significantly more efficient than dynamic binding.)

So 16 bytes of space overhead per node is worth it if you can avoid one 
indirect jump instruction? That seems like an odd trade-off from an 
efficiency point of view. (Program complexity is another matter...)

>    You don't need to mess with unions unless you really, really need to
> make the objects as small as physically possible.

Granted. That's why I wasn't going to try to do that.

>> Now for the /encoding/ part itself, I don't actually need a physical
>> tree. I have a vague recollection that last time I did this, I ended up
>> cheating and just storing a vector of codewords, and manually munging
>> that. It's a lot less elegant, but avoids dynamic allocation. (Or
>> rather, no it doesn't, but it hides it in STL containers, so you don't
>> have to do it manually.)
>
>    Using an array of objects (rather than individually allocated objects)
> doesn't completely avoid memory allocation, but it minimizes their amount,
> which is often very significant. (In other words, if your program makes
> 20 allocations instead of a million, it will have a significant impact
> on the speed of the program.)

Mmm, I hadn't even thought of using an /array/. I suppose the upper 
bound on the tree size is statically known, so why not?

>    If you really must have nodes of differing types, then it will become
> complicated from the point of view of memory management. Lack of garbage
> collection can be a b**** sometimes.

Ah well, that's why all large-scale applications are developed in C++, 
right? Because it doesn't force you to have garbage collection.

>    It's sometimes quite a bummer, but when writing efficient C++ you have
> to always think "how many memory allocations will this perform?"

Right. So what you're saying is that it's not dynamic binding /itself/ 
which is slow, but rather the dynamic allocations which necessarily go 
with it. (?)

>    Avoiding dynamic binding does not automatically mean that your program
> becomes more complicated and harder to maintain. In fact, it can sometimes
> mean the opposite. Sometimes your programs actually become *simpler* and
> much easier to understand. Full OOP (beyond simple encapsulation using
> classes) is not always the universal panacea for clarity and maintainability.
> (Of course this depends on each individual case.)

I usually find the OOP approach to be a good one. (Not always, of 
course.) Whether that's the type of code I write or what, I don't know.

Out of curiosity, if /you/ were writing a piece of code that's supposed 
to take a text string, parse it as an expression, and then execute the 
resulting expression, how would you implement that? The most obvious way 
is to make every valid kind of expression be a different class, and have 
an abstract base class with an "execute this" method, which gets 
implemented differently for each type of expression. But this 
necessarily involves dynamic binding and dynamic allocation, which you 
seem to make out is the Ultimate Evil to be avoided at all costs. So how 
would you do it?

(The obvious alternative is to design a single type that contains every 
field that any expression type will ever need, and write a giant switch 
statement to analyse each node to figure out how to execute it - which 
is exactly what OOP was designed to get rid of.)

>    But even then you have to think which design is easiest in terms of
> memory management. The less you have to manage memory manually, the
> better. Your program becomes safer and simpler.

Not manually managing memory certainly /is/ simpler than manually 
managing memory. No arguments there! ;-)

>> The problem is, I want to copy some data, but since I don't know what
>> class it belongs to, I have no idea how big it will be.
>
>    I didn't understand your problem from that description alone.

OK, well, if there is a single TreeNode class, I could write something like

   TreeNode(TreeNode t0, TreeNode t1)
   {
     child0 = new TreeNode;
     child1 = new TreeNode;
     *child0 = t0;
     *child1 = t1;
   }

If, however, the TreeNode class is abstract, obviously this won't work 
at all. I now need to know what the /actual/ type of t0 is before I can 
allocate sufficient space for it. (I'm also fuzzy on what happens when 
you try to delete a pointer - does it know what the "real" size of the 
object is, or does it use the declared type of the pointer?)

>>>     Now, writing a class that properly manages its dynamically allocated
>>> memory is a non-trivial task of its own.
>
>> Is that not just a case of allocating the memory correctly in the
>> constructor, and freeing it properly in the destructor? (I mean,
>> assuming nobody tries to copy the object or free its dynamic memory or
>> anything like that...)
>
>    The simplest design is to delete the allocated memory in the destructor
> (it doesn't really matter where inside the class the memory is allocated
> as long as the pointer is kept as 0 when there's nothing allocated) and
> then disabling the copy constructor and assignment operators. (In C++98
> this is done by declaring them private and not implementing them. In C++11
> you can explicitly express this with a keyword.)
>
>    Often this is enough. However, sometimes you would want to be able
> to copy and assign objects of that class type around. That's where the
> non-triviality kicks in.

Right. Yeah, I can see how that might get confusing - especially if 
you're trying to minimise actual data copying...


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:42:34
Message: <4f5fa32a$1@news.povray.org>
On 13/03/2012 17:31, Warp wrote:
> Warp<war### [at] tagpovrayorg>  wrote:
>>    The first problem is: How should the object be copied? There are many
>> possibilities:
>
>    If you are wondering which solution the STL data containers use,
> it's usually just a simple deep-copy whenever the container is copied
> or assigned.

Just to be picky: I'm presuming that it's a "deep" copy as far as 
copying the container itself. Presumably what happens to the elements 
depends on what their copy constructor implements. (?)


Post a reply to this message

From: nemesis
Subject: Re: A tale of two cities
Date: 13 Mar 2012 15:59:35
Message: <4f5fa727$1@news.povray.org>
Orchid Win7 v1 escreveu:
> On 13/03/2012 19:27, nemesis wrote:
>> ah, children from the 90's...
> 
> I wish. :-P

ok, old fart.

> Seriously. Visual Studio manages to be responsive enough, and not eat 
> half my RAM. NetBeans can't. IMHO, that makes NetBeans inferior.

Windows comes with the .NET libraries used by VS.  It's also a native 
program, rather than one running on a VM.

>> Here's a challenge for you. What do these haskell snippets are supposed
>> to do?
>>
>> snippet 1:
>>
>> ((.)$(.))
> 
> ASCII art? ;-)

actually, I thought it was some perl idiom. :)

if it was a bit more concise, it'd give you a nice pair of boobies:
(.)(.)

> In fact, the "$" is necessary. Either way, this takes a 3-argument 
> function, the first argument to the function, a function that transforms 
> some type into the type of the second argument, and a suitable argument 
> to transform. Or, in symbols,
> 
> (x -> y -> z) -> x -> (j -> y) -> y -> z

haha, you already new that from the haskellwiki. :p

>> snippet 2:
>>
>> f >>= a . b . c =<< g
> 
> Without knowing what the variables are bound to, this cannot be 
> answered. It would be like saying "what does Foo(Bar(5)) do?"

ok, both come from here:

http://www.haskell.org/haskellwiki/Pointfree#The_owl
http://www.haskell.org/haskellwiki/Pointfree#Squish

>> and for a bonus, guess what this one does:
>>
>> import System.Environment
>>
>> foo n = 0 % (0 # (1,0,1)) where
>> i%ds
>> | i >= n = []
>> | True = (concat h ++ "\t:" ++ show j ++ "\n") ++ j%t
>> where k = i+10; j = min n k
>> (h,t) | k > n = (take (n`mod`10) ds ++ replicate (k-n) " ",[])
>> | True = splitAt 10 ds
>> j # s | n>a || r+n>=d = k # t
>> | True = show q : k # (n*10,(a-(q*d))*10,d)
>> where k = j+1; t@(n,a,d)=k&s; (q,r)=(n*3+a)`divMod`d
>> j&(n,a,d) = (n*j,(a+n*2)*y,d*y) where y=(j*2+1)
>>
>> main = putStr.foo.read.head =<< getArgs
> 
> That's not even parsable. (Indentation is significant, remember?)

ah, seems indentation is lost (too bad for haskell).  But nice style on 
giving up.

>>> Yes, Java /still/ sucks. :-P
>>
>> Yes and that is a feature by design.
> 
> O RLY?

Yes, so that your hired slaves can't cut the pulses and get free.

>> What doesn't suck is the JVM and the tens of thousands of useful libs
>> that run atop it. It's the only truly cross-platform performant VM out
>> there. Think about it, libs you don't actually need to recompile on your
>> machine.
> 
> Ha! If only... They don't say "write once, test everywhere" for nothing. 
> ;-)

seems like most of the thousands of open-source java libs are well 
tested already.

> I hear there are other languages that target the JVM. Presumably you 
> still can't use any of the existing libraries though. (Not that any of 
> them are much good.)

yes, you are likely to use java libs.

> Oh, Haskell? Yeah, I gather a few people have tried to target the JVM 
> with it. Nothing production-grade currently exists, however.
> 
>> BTW, Ant is yet another example of XML-madness: it's basically a verbose
>> XML makefile for java.
> 
> Oh well. At least you don't need tab characters. :-P

says the haskell programmer... :p

-- 
a game sig: http://tinyurl.com/d3rxz9


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: A tale of two cities
Date: 13 Mar 2012 16:37:07
Message: <4f5faff3$1@news.povray.org>
>>> ah, children from the 90's...
>>
>> I wish. :-P
>
> ok, old fart.

Thanks for making me feel better. :-P

>> Seriously. Visual Studio manages to be responsive enough, and not eat
>> half my RAM. NetBeans can't. IMHO, that makes NetBeans inferior.
>
> Windows comes with the .NET libraries used by VS. It's also a native
> program, rather than one running on a VM.

You know, people say "oh, Java isn't slow". And then this happens...

Also, about this "Windows comes with the .NET libraries". If that's so, 
then why did I have to wait 20 minutes for it to download .NET when I 
installed it?

>>> snippet 1:
>>>
>>> ((.)$(.))
>>
>> ASCII art? ;-)
>
> actually, I thought it was some perl idiom. :)

The question is, who the heck writes code like that anyway? (Except to 
show off.)

> if it was a bit more concise, it'd give you a nice pair of boobies:

Hey, that's what it looked like in the first place. But rich boobies. ;-)

>> In fact, the "$" is necessary. Either way, this takes a 3-argument
>> function, the first argument to the function, a function that
>> transforms some type into the type of the second argument, and a
>> suitable argument to transform. Or, in symbols,
>>
>> (x -> y -> z) -> x -> (j -> y) -> y -> z
>
> haha, you already new that from the haskellwiki. :p

Erm, no... It's a simple question of type inference. I mean, c'mon, it's 
not exactly a complicated code fragment. It's two function calls.

>> That's not even parsable. (Indentation is significant, remember?)
>
> ah, seems indentation is lost (too bad for haskell). But nice style on
> giving up.

Well, yeah, because even if I could understand it, that wouldn't prove 
anything to anyone.

>>>> Yes, Java /still/ sucks. :-P
>>>
>>> Yes and that is a feature by design.
>>
>> O RLY?
>
> Yes, so that your hired slaves can't cut the pulses and get free.

Wuh?

>> Ha! If only... They don't say "write once, test everywhere" for
>> nothing. ;-)
>
> seems like most of the thousands of open-source java libs are well
> tested already.

Wait - there are open-source Java libs now?

(Last time I looked at Java, all anyone ever used it for was pointless 
Tic-Tac-Toe applets. Nobody ever wrote actual large applications with 
it, just small toy examples.)

>>> BTW, Ant is yet another example of XML-madness: it's basically a verbose
>>> XML makefile for java.
>>
>> Oh well. At least you don't need tab characters. :-P
>
> says the haskell programmer... :p

What? Tab characters are explicitly disallowed in Haskell. :-P


Post a reply to this message

From: nemesis
Subject: Re: A tale of two cities
Date: 13 Mar 2012 17:24:34
Message: <4f5fbb12$1@news.povray.org>
Orchid Win7 v1 escreveu:
>>>> ah, children from the 90's...
>>>
>>> I wish. :-P
>>
>> ok, old fart.
> 
> Thanks for making me feel better. :-P

I'm even older than you (not by much actually) but have a far better 
sense of humor.  Better now? :)

>>> Seriously. Visual Studio manages to be responsive enough, and not eat
>>> half my RAM. NetBeans can't. IMHO, that makes NetBeans inferior.
>>
>> Windows comes with the .NET libraries used by VS. It's also a native
>> program, rather than one running on a VM.
> 
> You know, people say "oh, Java isn't slow". And then this happens...

It's one of the fastest languages on the shootout game.

> Also, about this "Windows comes with the .NET libraries". If that's so, 
> then why did I have to wait 20 minutes for it to download .NET when I 
> installed it?

older Windows?  anyway, .NET does not count when looking at the memory 
statistcs of a program that uses it.  It's "part" of Windows.  That's 
why you look at VS and it looks fine.  That's why you look at Firefox or 
Netbeans or some other foreign app and it looks like it's sucking all 
your memory:  their particular libs are alien to Windows and thus are 
taken into account when showing statistcs.  Not so with microsoft libs, 
so VS and IE look pretty lightweight.

they play dirty.

>>> (x -> y -> z) -> x -> (j -> y) -> y -> z
>>
>> haha, you already new that from the haskellwiki. :p
> 
> Erm, no... It's a simple question of type inference.

I prefer to leave that to the compiler or interpreter.  Better yet, I 
prefer not to think of types. :)

> I mean, c'mon, it's 
> not exactly a complicated code fragment. It's two function calls.

two function calls that take other functions and return other functions 
and ... well, you get the idea.

>>> That's not even parsable. (Indentation is significant, remember?)
>>
>> ah, seems indentation is lost (too bad for haskell). But nice style on
>> giving up.
> 
> Well, yeah, because even if I could understand it, that wouldn't prove 
> anything to anyone.

BTW, I looked up my post and indentation was fine.  But anyway, it's the 
pidigits haskell program at the shootout:

http://shootout.alioth.debian.org/u64q/benchmark.php?test=pidigits&lang=ghc

>>>>> Yes, Java /still/ sucks. :-P
>>>>
>>>> Yes and that is a feature by design.
>>>
>>> O RLY?
>>
>> Yes, so that your hired slaves can't cut the pulses and get free.
> 
> Wuh?

well, they do try to cut their pulses, but the language doesn't afford 
that.  Nor shooting on the foot.

>>> Ha! If only... They don't say "write once, test everywhere" for
>>> nothing. ;-)
>>
>> seems like most of the thousands of open-source java libs are well
>> tested already.
> 
> Wait - there are open-source Java libs now?
> 
> (Last time I looked at Java, all anyone ever used it for was pointless 
> Tic-Tac-Toe applets. Nobody ever wrote actual large applications with 
> it, just small toy examples.)

Earth to Andrew, Earth to Andrew!  An import message has been delivered: 
  this is not 1964 anymore.

Hint:  Apache once was a (patchy) http server.  Now it's one huge java shop.

After Microsoft shoved Java away from the desktop, it hid on the server 
(where it shoved Perl away).

>>>> BTW, Ant is yet another example of XML-madness: it's basically a 
>>>> verbose
>>>> XML makefile for java.
>>>
>>> Oh well. At least you don't need tab characters. :-P
>>
>> says the haskell programmer... :p
> 
> What? Tab characters are explicitly disallowed in Haskell. :-P

except where needed.

I prefer proper free-form parentheses. :)

-- 
a game sig: http://tinyurl.com/d3rxz9


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 00:32:46
Message: <4f601f6e@news.povray.org>
Am 13.03.2012 11:11, schrieb Invisible:

> The real sticking point was when I started trying to use abstract
> classes. It seems that you cannot have a variable of an abstract class.
> (Because creating that variable would require creating an instance of an
> abstract class, which is illegal.) You can only have a variable that
> /points to/ such a value. (Because then what it points to can actually
> be some concrete subclass.)
>
> That's all fine and logical and everything, but there's a nasty snag:
> Now you have to care about memory management. And there's no way around it.

Forget all you know about classic C pointers; instead, try the C++11 
(aka C++0x) shared pointers - they'll take care of all the disposing 
stuff. (If C++0x is not an option, use the boost library; C++0x took 
them right from there).

Instead of e.g.

     MyVirtualClass* o1 = new MySubClass(...);
     MyVirtualClass* o2 = o1;
     o1->doThis();
     o2->doThat();
     dispose o2; o1 = null; o2 = null;

you'd write

     shared_ptr<MyVirtualClass> o1(new MySubClass(...));
     shared_ptr<MyVirtualClass> o2(o1);
     o1->doThis();
     o2->doThat();
     o1 = null;
     o2 = null;

Note that the dispose is gone for good. Shared pointers use reference 
counters to accomplish this feat.

To save you some typing, you may want to use

     typedef shared_ptr<MyVirtualClass> MyVirtualClassPtr;

(Caveat: Assignments of shared pointers are a little tricky, as the 
assignment operator "o1 = o2;" is actually implemented as a swap 
operation; you'll need to use "o1 = shared_ptr<MyVirtualClass>(o2);" 
instead to clone a pointer.)

There is also a complementary weak_ptr, which allows the referenced 
object to be destroyed. To try to access the object, get a shared_ptr 
from the weak_ptr, verify that the shared_ptr is non-null and access the 
object.

> Like VS, asking NetBeans for a basic project generates a plateful of
> useless code that you then have to waste time deleting. (Apparently
> there's an Ant script somewhere too... whatever the hell that is.) It
> also sets the tab depth far, far too deep. But unlike VS, it also seems
> to /insist/ on incorrectly putting the open bracket on the same line as
> the declaration it begins. (This incorrect practise is also common in
> C++, and yet I didn't seem to have this problem with VS.) It's easy
> enough to manually fix, I suppose.

There's nothing "incorrect" about that way of placing braces, even in 
C++. It's syntactically correct, so say what you will.

As for Java, it's actually /the/ official curly braces convention, as 
recommended by Sun and later Oracle.

> So there we are. I doubt I'd remember much about the AWT (although,
> didn't they deprecate that in favour of Swing?),

The JAVA API has a rich history of deprecating interfaces, deprecating 
interfaces designed to replace deprecated interfaces, and un-deprecating 
deprecated interfaces. I wouldn't be surprised if AWT was among the latter.

> but I can certainly
> still write algorithmic code in Java without much ado. Maybe today I'll
> try something more ambitious with it. If I can avoid throwing the IDE
> out of a window.

Try Eclipse. Somehow it seems to be the unofficial standard IDE. (Never 
tried it myself in depth though; it has that very special 
Open-Software-Project air about it that somehow makes my skin crawl ever 
since I tried OpenOffice for real.)

> (Is it just me? "Net Beans"? It's an IDE. What the /hell/ does that have
> to do with networking? The "beans" part I kinda get; everything
> Java-related has to be themed on coffee or coffee beans. But why "net"?)

Maybe because "The NetBeans project consists of an open-source IDE and 
an application platform that enable developers to rapidly create web, 
enterprise, desktop, and mobile applications using the Java platform [...]"?


Anyway, I personally stick to IDEs developed by software development 
companies (and I mean companies that develop other stuff besides 
programming languages and IDEs). So far the best IDE experience has been 
Visual Studio for C#. One might snarl at the company's marketing 
strategies, but they seem to know what helps software developers to be 
productive.


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 00:47:00
Message: <4f6022c4@news.povray.org>
Am 13.03.2012 20:40, schrieb Orchid Win7 v1:

>> import System.Environment
>>
>> foo n = 0 % (0 # (1,0,1)) where
>> i%ds
>> | i >= n = []
>> | True = (concat h ++ "\t:" ++ show j ++ "\n") ++ j%t
>> where k = i+10; j = min n k
>> (h,t) | k > n = (take (n`mod`10) ds ++ replicate (k-n) " ",[])
>> | True = splitAt 10 ds
>> j # s | n>a || r+n>=d = k # t
>> | True = show q : k # (n*10,(a-(q*d))*10,d)
>> where k = j+1; t@(n,a,d)=k&s; (q,r)=(n*3+a)`divMod`d
>> j&(n,a,d) = (n*j,(a+n*2)*y,d*y) where y=(j*2+1)
>>
>> main = putStr.foo.read.head =<< getArgs
>
> That's not even parsable. (Indentation is significant, remember?)

Yuck - I hate it when languages do that.

> Darren claims they committed to a feature freeze too soon. I don't know
> about the low-level details of the JVM. But I gather that, say, adding
> Java generics required lots of ugly hacks so it didn't break compatibility.

Guess how many ugly hacks C++ relies on to not break compatibility with 
classic library formats...

> I hear there are other languages that target the JVM. Presumably you
> still can't use any of the existing libraries though. (Not that any of
> them are much good.)

The fun is that you can. The bane is that you might have to.

> Oh, Haskell? Yeah, I gather a few people have tried to target the JVM
> with it. Nothing production-grade currently exists, however.

Is there any such thing as a production-grade Haskell implementation?


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 00:53:26
Message: <4f602446@news.povray.org>
Am 13.03.2012 21:37, schrieb Orchid Win7 v1:

> Wait - there are open-source Java libs now?
>
> (Last time I looked at Java, all anyone ever used it for was pointless
> Tic-Tac-Toe applets. Nobody ever wrote actual large applications with
> it, just small toy examples.)

You've never heard of Java enterprise application servers, have you?


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 01:48:36
Message: <4f603134@news.povray.org>
Am 13.03.2012 20:41, schrieb Orchid Win7 v1:

> (I'm also fuzzy on what happens when
> you try to delete a pointer - does it know what the "real" size of the
> object is, or does it use the declared type of the pointer?)

Just like free() in C, the delete operator in C++ frees whatever memory 
was originally allocated to the object, so you don't need to worry about 
/that/.

What you /should/ worry about, however, is which destructor will be 
called: Make sure to equip all of your virtual classes with a virtual 
destructor, otherwise the C++ standard guarantees for nothing.

(For non-virtual classes it is good practice to define a protected 
non-virtual destructor instead, just to be sure.)


Post a reply to this message

From: Darren New
Subject: Re: A tale of two cities
Date: 14 Mar 2012 03:14:07
Message: <4f60453f$1@news.povray.org>
On 3/13/2012 3:11, Invisible wrote:
> just runs the downloader for the /real/ installation program.

At least MS gives you a choice. They do that because you can pick to 
download C++, C#, the IDE, and the SQL server, and it'll download just the 
parts you need without duplicating them. Plus it downloads the right version 
for your OS, etc.

> business. Now, I'm not saying NetBeans is /inefficient/, but swallowing
> 200MB of RAM just because I double-clicked the icon to open the IDE does
> seem /just a tad excessive/ to me.

Only 200? I think the Eclipse at work takes 550M to 600M to start up.

> trying to actually /do/ stuff, the IDE seemed unacceptably unresponsive.

Try Eclipse. Try pasting a comment from one part of the file to the other 
making it go "unresponsive" long enough that Gnome asks if you want to kill it.

>  (Apparently there's an Ant
> script somewhere too... whatever the hell that is.)

It's an attempt at improving Make without actually fixing the major problems 
with Make.

> Or rather, I'm impressed at the IDE. Implementing array copying as a static
> method on a general utility class? Yeah, /that/ sounds like fantastic OO
> library design! :-P

Wait until you get into the generics, where you do things like turn a list 
of Freds into an array of Freds by invoking

   fredList.toArray(new Fred[]{});

i.e., by passing an empty array of Freds to the function in order to pick 
the right generic to return. Yes, you actually put an empty array on the 
heap simply to pass compile-time type data to pick the right method in a 
language that supports generics. Because there's no syntax for
    fredList.toArray<Fred>();

> the program. VS did all of this and more. :-P

Over the weekend, I wrote a program to take a couple CSV files, munge them, 
and stick them into some XML I could pull into the tax authority's forms, in 
C#.   It was like surfacing from under quicksand to use VS instead of 
Eclipse. I hadn't realized just *how* much Eclipse kills me at work compared 
to something designed by CHI experts instead of hackers.

I have a big text file with all my Eclipse hates on my desktop, just keeping 
track for a good rant some day.

> So there we are. I doubt I'd remember much about the AWT (although, didn't
> they deprecate that in favour of Swing?),

Yes, in spite of promising on day 1 that they'd never do that.

-- 
Darren New, San Diego CA, USA (PST)
   People tell me I am the counter-example.


Post a reply to this message

From: Darren New
Subject: Re: A tale of two cities
Date: 14 Mar 2012 03:20:10
Message: <4f6046aa@news.povray.org>
On 3/13/2012 14:24, nemesis wrote:
> older Windows? anyway, .NET does not count when looking at the memory
> statistcs of a program that uses it. It's "part" of Windows. That's why you
> look at VS and it looks fine.

I'm pretty sure that's not true. What *is* true is that .NET DLLs load as 
shard DLLs, and java .class files can't do that, since they're data.

-- 
Darren New, San Diego CA, USA (PST)
   People tell me I am the counter-example.


Post a reply to this message

From: Darren New
Subject: Re: A tale of two cities
Date: 14 Mar 2012 03:30:57
Message: <4f604931$1@news.povray.org>
On 3/13/2012 21:32, clipka wrote:
> Try Eclipse. Somehow it seems to be the unofficial standard IDE. (Never
> tried it myself in depth though; it has that very special
> Open-Software-Project air about it that somehow makes my skin crawl ever
> since I tried OpenOffice for real.)

It's not only that, but it's also a whole plug-in mentality.

You go to the project explorer with the tree view of your project's classes. 
You double-click a class to open it. You type Ctrl-F and start typing the 
name of the method you're looking for. What do you think happens? If you 
answer "Well, the focus was left on the project explorer because Eclipse is 
so modular it doesn't know where to put the focus, so your search string is 
in the wrong window", give yourself a cigar. If you continued "... and so 
you now have to click *three times* in the class window to change focus, 
once to close the search box in the project window, once to put the focus in 
the class window, and once to put it in the edit pane of the class window, 
and *now* you can type Ctrl-F", you may light your cigar.

> Anyway, I personally stick to IDEs developed by software development
> companies (and I mean companies that develop other stuff besides programming
> languages and IDEs). So far the best IDE experience has been Visual Studio
> for C#. One might snarl at the company's marketing strategies, but they seem
> to know what helps software developers to be productive.

Indeed. Or use an IDE by a group that actually has a CHI/UI expert on board.


-- 
Darren New, San Diego CA, USA (PST)
   People tell me I am the counter-example.


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:20:44
Message: <4f6062ec$1@news.povray.org>
>> You know, people say "oh, Java isn't slow". And then this happens...
>
> It's one of the fastest languages on the shootout game.

1. Micro-benchmarks are one thing. Large applications are another.

2. It seems the fastest is actually Fortran. (?!) Followed by C++. 
Followed by C. Followed by ATS and ADA. Only then do we get to Java, at 
70% slower.

(Mind you, Haskell is sitting there at 180% slower, so...)

>> Also, about this "Windows comes with the .NET libraries". If that's
>> so, then why did I have to wait 20 minutes for it to download .NET
>> when I installed it?
>
> older Windows? anyway, .NET does not count when looking at the memory
> statistcs of a program that uses it. It's "part" of Windows.

> they play dirty.

No, I'm pretty sure that's not correct.

The .NET libraries probably show up as shared RAM rather than private 
RAM, but they do still show up.

>>>> (x -> y -> z) -> x -> (j -> y) -> y -> z
>>>
>>> haha, you already new that from the haskellwiki. :p
>>
>> Erm, no... It's a simple question of type inference.
>
> I prefer to leave that to the compiler or interpreter.

Alrighty then.

http://tryhaskell.org/

 > :t ((.)$(.))

:: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c

Easy.

> Better yet, I prefer not to think of types. :)

A Haskell programmer not thinking about types is like an assembly 
programmer not thinking about processor registers. It is nonsensical.

>> I mean, c'mon, it's not exactly a complicated code fragment. It's two
>> function calls.
>
> two function calls that take other functions and return other functions
> and ... well, you get the idea.

Quite. I'm still waiting on the "who the hell writes code like this 
anyway?" part.

> BTW, I looked up my post and indentation was fine. But anyway, it's the
> pidigits haskell program at the shootout:

Ah yes. The great language shootout. An elaborate benchmark for 
measuring how many hackers are available to work on each programming 
language. ;-)

>> Wait - there are open-source Java libs now?
>>
>> (Last time I looked at Java, all anyone ever used it for was pointless
>> Tic-Tac-Toe applets. Nobody ever wrote actual large applications with
>> it, just small toy examples.)
>
> Earth to Andrew, Earth to Andrew! An import message has been delivered:
> this is not 1964 anymore.

Well, given that Java 1.0 dates to 1995, nobody would be arguing about 
Java back in the 60s. :-P

> Hint: Apache once was a (patchy) http server. Now it's one huge java shop.

Hint: When anybody says "Apache", they almost always mean "the Apache 
web server". Few people seem to realise that the Apache foundation even 
/make/ anything else. That's how popular their other stuff is.

> After Microsoft shoved Java away from the desktop, it hid on the server
> (where it shoved Perl away).

It is also news to me that Perl has gone anywhere but up. :-P

>>>> Oh well. At least you don't need tab characters. :-P
>>>
>>> says the haskell programmer... :p
>>
>> What? Tab characters are explicitly disallowed in Haskell. :-P
>
> except where needed.

Um, no. If your source file contains any tab characters, the compiler 
spits out an error message and refuses to compile it.

> I prefer proper free-form parentheses. :)

OK. So turn off the layout rule. :-P


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:25:59
Message: <4f606427@news.povray.org>
On 14/03/2012 04:53 AM, clipka wrote:
> Am 13.03.2012 21:37, schrieb Orchid Win7 v1:
>
>> Wait - there are open-source Java libs now?
>>
>> (Last time I looked at Java, all anyone ever used it for was pointless
>> Tic-Tac-Toe applets. Nobody ever wrote actual large applications with
>> it, just small toy examples.)
>
> You've never heard of Java enterprise application servers, have you?

I've heard of them - but I have no idea what the hell they are. Last 
time I checked, "enterprise" refers either to NCC-1701-D, a galaxy-class 
starship of the United Federation of Planets, or to a piece of software 
which is pointlessly over-engineered, over-complex, over-priced, and 
sold by pushy over-paid salesmen in bad suits.


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:28:56
Message: <4f6064d8@news.povray.org>
>> That's not even parsable. (Indentation is significant, remember?)
>
> Yuck - I hate it when languages do that.

I thought I would hate it... but when not used in insane ways, it 
actually works quite well. I mean, most programmers indent stuff 
sensibly /anyway/, so having it be significant just means that you can 
avoid having to type a few extra delimiters.

...except in those handful of cases where how /you/ want to indent 
doesn't match what the compiler wants. /Then/ it becomes annoying.

>> Darren claims they committed to a feature freeze too soon. I don't know
>> about the low-level details of the JVM. But I gather that, say, adding
>> Java generics required lots of ugly hacks so it didn't break
>> compatibility.
>
> Guess how many ugly hacks C++ relies on to not break compatibility with
> classic library formats...

Well, yeah. But nobody tries to claim that C is a good programming la... 
oh, wait.

>> I hear there are other languages that target the JVM. Presumably you
>> still can't use any of the existing libraries though. (Not that any of
>> them are much good.)
>
> The fun is that you can. The bane is that you might have to.

LOL!

>> Oh, Haskell? Yeah, I gather a few people have tried to target the JVM
>> with it. Nothing production-grade currently exists, however.
>
> Is there any such thing as a production-grade Haskell implementation?

Sure. Several companies are using GHC to produce mission-critical (and 
often security-critical or even safety-critical) production code.


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:35:37
Message: <4f606669$1@news.povray.org>
>> Anyway, I personally stick to IDEs developed by software development
>> companies (and I mean companies that develop other stuff besides
>> programming languages and IDEs).
>
> Indeed. Or use an IDE by a group that actually has a CHI/UI expert on
> board.

You know, I spent an entire semester studying "human-computer 
interaction" without once comprehending WTF the subject was supposed to 
be about. Perhaps if they'd made us use NetBeans and then compile a list 
of all the things that are wrong with it, /then/ we would have understood...

Although... Zimin Wu /did/ look like he was actually a stage magician. I 
kept expecting him to be like "and, arh, here we have arh typocarh 
usarh, and arh, here we have A FLOWER!" and rip a big bunch of paper 
flowers out of his sleeve. But, weirdly, he never actually did this...


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:42:20
Message: <4f6067fc@news.povray.org>
On 14/03/2012 07:14 AM, Darren New wrote:
> On 3/13/2012 3:11, Invisible wrote:
>> just runs the downloader for the /real/ installation program.
>
> At least MS gives you a choice. They do that because you can pick to
> download C++, C#, the IDE, and the SQL server, and it'll download just
> the parts you need without duplicating them. Plus it downloads the right
> version for your OS, etc.

Usually if you hunt around the MS site, you can find the "network 
administrator" download, "for IT professionals", which /actually/ 
downloads enough data for offline installation. Because, let's face it, 
only an IT professional would have the technical skill to know that 
there's a difference between downloading an installer and downloading a 
downloader for an installer... oh, wait.

> Only 200? I think the Eclipse at work takes 550M to 600M to start up.

> Try Eclipse. Try pasting a comment from one part of the file to the
> other making it go "unresponsive" long enough that Gnome asks if you
> want to kill it.

Oh, that's cute. No wonder I hear nothing but good things about 
Eclipse... I gather there's even a Haskell plugin for it. (I bit it 
doesn't /do/ anything though.)

>> (Apparently there's an Ant
>> script somewhere too... whatever the hell that is.)
>
> It's an attempt at improving Make without actually fixing the major
> problems with Make.

Well, they fixed /one/ major problem: Text processing tools which turn 
tabs into spaces. ;-)

> Wait until you get into the generics

Uh, yeah.

It seems either they implemented everything twice (once with, and once 
without generics), or it's actually legal to not specify type parameters 
and then they default to Object. Which, either way, is highly 
counter-intuitive...

> It was like surfacing from under quicksand to use VS
> instead of Eclipse. I hadn't realized just *how* much Eclipse kills me
> at work compared to something designed by CHI experts instead of hackers.

I don't know about CHI experts - more like unpaid beta testers. ;-)

> I have a big text file with all my Eclipse hates on my desktop, just
> keeping track for a good rant some day.

And by "rant" you of course mean "shotgun rampage"? ;-)

>> So there we are. I doubt I'd remember much about the AWT (although,
>> didn't they deprecate that in favour of Swing?),
>
> Yes, in spite of promising on day 1 that they'd never do that.

Ah, but did they formally deprecate it, or just "strongly encourage you 
not to use it"? ;-)


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:43:14
Message: <4f606832$1@news.povray.org>
On 14/03/2012 05:48 AM, clipka wrote:

> (For non-virtual classes it is good practice to define a protected
> non-virtual destructor instead, just to be sure.)

Is it wrong that whenever I read a sentence like this, I can hear a 
voice say "nuke it from space - it's the only way to be sure"?


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 05:55:23
Message: <4f606b0b$1@news.povray.org>
>> That's all fine and logical and everything, but there's a nasty snag:
>> Now you have to care about memory management. And there's no way
>> around it.
>
> Forget all you know about classic C pointers;

That shouldn't take long. :-P

> Note that the dispose is gone for good. Shared pointers use reference
> counters to accomplish this feat.

Every time I hear somebody say this, a part of me wants to scream "you 
/do/ understand that reference counting doesn't actually work, right?"

> There's nothing "incorrect" about that way of placing braces, even in
> C++. It's syntactically correct, so say what you will.

Writing the entire program in one source file on a single 435,235,342 
character line is "syntactically correct". But no sane programmer would 
ever do such a horrifying thing. :-P

> The JAVA API has a rich history of deprecating interfaces, deprecating
> interfaces designed to replace deprecated interfaces, and un-deprecating
> deprecated interfaces. I wouldn't be surprised if AWT was among the latter.

Oh yes. I don't remember the names exactly, but I can clearly remember 
how one release of Java had BufferedInputStream and friends. And then in 
the next release, they deprecated that and gave you BufferedReader 
instead. And then in the next release, they deprecated BufferedReader 
and UNdeprecated BufferedInputStream again. (Pro tip: You should /never/ 
need to UNdeprecate something!)

Of course, when I was using Java, it was still quite new. I'd be 
interested to know whether the libraries eventually settled down and 
they stopped doing crap like this, or... ?

> Try Eclipse. Somehow it seems to be the unofficial standard IDE. (Never
> tried it myself in depth though; it has that very special
> Open-Software-Project air about it that somehow makes my skin crawl ever
> since I tried OpenOffice for real.)

Hahaha. "That special OSS air". Yep, NetBeans has that. I don't know 
whether it's the cute but poorly-drawn icons that seem bigger than 
necessary. Or the slightly odd grouping of user preferences. Or the way 
that different parts of the IDE contradict each other as to the current 
status of the code, because each part is out of date by a different 
amount...

> Anyway, I personally stick to IDEs developed by software development
> companies (and I mean companies that develop other stuff besides
> programming languages and IDEs). So far the best IDE experience has been
> Visual Studio for C#. One might snarl at the company's marketing
> strategies, but they seem to know what helps software developers to be
> productive.

I don't know about "what helps software developers to be productive"... 
How about "what makes software developers buy our product rather than 
somebody else's"? Or even "what makes software developers develop for 
our platform rather than somebody else's"? ;-)

The entire MS business model fundamentally depends on getting everyone 
to use the MS platform, and then be locked in. Well, if your platform 
has naff-all software for it, nobody will buy it. But if your platform 
has all the best stuff, people will pay. And then be trapped. So it pays 
(literally) to make it easy for people to write code for your platform 
and only your platform. >:-D


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 14 Mar 2012 09:44:37
Message: <4f60a0c4@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
> On 13/03/2012 17:31, Warp wrote:
> > Warp<war### [at] tagpovrayorg>  wrote:
> >>    The first problem is: How should the object be copied? There are many
> >> possibilities:
> >
> >    If you are wondering which solution the STL data containers use,
> > it's usually just a simple deep-copy whenever the container is copied
> > or assigned.

> Just to be picky: I'm presuming that it's a "deep" copy as far as 
> copying the container itself. Presumably what happens to the elements 
> depends on what their copy constructor implements. (?)

  The container object manages dynamically allocated memory, and such
objects can be copied. Naturally I was referring to what type of copying
they perform in that case.

  The elements themselves use whatever copying mechanism they have been
defined to have.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 14 Mar 2012 10:15:22
Message: <4f60a7f9@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
> So 16 bytes of space overhead per node is worth it if you can avoid one 
> indirect jump instruction?

  No, it's worth it if you can avoid one extraneous memory allocation
(or having to manage the allocated memory manually).

  A memory allocation will easily consume those 16 bytes of extra space
anyways (the memory allocator bookkeeping, memory alignment, and the pointer
used to refer to the allocated object), so it's not like you are gaining
anything.

> Mmm, I hadn't even thought of using an /array/. I suppose the upper 
> bound on the tree size is statically known, so why not?

  The array doesn't necessarily have to be fixed in size.

> >    It's sometimes quite a bummer, but when writing efficient C++ you have
> > to always think "how many memory allocations will this perform?"

> Right. So what you're saying is that it's not dynamic binding /itself/ 
> which is slow, but rather the dynamic allocations which necessarily go 
> with it. (?)

  Calling a virtual function is in practice not any slower than calling
a regular function.

  Calling 'new', however, can be really slow (comparatively speaking).

  If you can reduce x millions of 'new' calls into eg. log(x millions) of
'new' calls, your program will probably become much faster.

> Out of curiosity, if /you/ were writing a piece of code that's supposed 
> to take a text string, parse it as an expression, and then execute the 
> resulting expression, how would you implement that?

  You mean like this? http://warp.povusers.org/FunctionParser/

> The most obvious way 
> is to make every valid kind of expression be a different class, and have 
> an abstract base class with an "execute this" method, which gets 
> implemented differently for each type of expression. But this 
> necessarily involves dynamic binding and dynamic allocation, which you 
> seem to make out is the Ultimate Evil to be avoided at all costs. So how 
> would you do it?

  If the parser consists of some dozens expression parsers which are added
to the core module once at program start, then the slowness of memory
allocation becomes completely irrelevant. You are not performing millions
of 'new' operations, only a few dozen of them. The virtual function calls
themselves are pretty efficient. (What you *should* avoid is calling 'new'
and 'delete' during the parsing, if you want it to be as fast as possible.)

  The major design issue becomes the management of those dynamically
allocated objects. (Smart pointers may be a good solution to this.)

  Of course there are other approaches which are more efficient in terms
of memory usage, but they are usually less flexible (in that it's harder
to add new expressions to the parser from the outside without modifying
the source code of the parser module).

> OK, well, if there is a single TreeNode class, I could write something like

>    TreeNode(TreeNode t0, TreeNode t1)
>    {
>      child0 = new TreeNode;
>      child1 = new TreeNode;
>      *child0 = t0;
>      *child1 = t1;
>    }

  Since TreeNode there is managing dynamically allocated memory, you'll
have to write a proper copy constructor and assignment operator or else
you have a leak and/or accesses to deleted memory. (And as I said in my
previous post, that's not trivial because of all the options you have.)

> If, however, the TreeNode class is abstract, obviously this won't work 
> at all. I now need to know what the /actual/ type of t0 is before I can 
> allocate sufficient space for it.

  Well, that's easy. You should do this:

    class TreeNode
    {
     protected:
        virtual TreeNode* clone() const = 0;

     public:
         TreeNode(const TreeNode& t0, const TreeNode& t1):
             child0(t0.clone()),
             child1(t1.clone())
         {}

         // Implement destructor, copy constructor and assignment
         // operator appropriately here.
    };

  Then every inherited class implements that 'clone()' method like:

    class FancyNode: public TreeNode
    {
     protected:
        virtual TreeNode* clone() const
        {
            return new FancyNode(*this);
        }
    };

> (I'm also fuzzy on what happens when 
> you try to delete a pointer - does it know what the "real" size of the 
> object is, or does it use the declared type of the pointer?)

  If the pointer is handling a dynamically bound object, then the
destructor of the base class has to be virtual. Then 'delete' is able
to destroy the object appropriately.

-- 
                                                          - Warp


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 10:24:26
Message: <4f60aa1a@news.povray.org>
Am 14.03.2012 10:26, schrieb Invisible:

>>> (Last time I looked at Java, all anyone ever used it for was pointless
>>> Tic-Tac-Toe applets. Nobody ever wrote actual large applications with
>>> it, just small toy examples.)
>>
>> You've never heard of Java enterprise application servers, have you?
>
> I've heard of them - but I have no idea what the hell they are. Last
> time I checked, "enterprise" refers either to NCC-1701-D, a galaxy-class
> starship of the United Federation of Planets, or to a piece of software
> which is pointlessly over-engineered, over-complex, over-priced, and
> sold by pushy over-paid salesmen in bad suits.

It's essentially a framework for companies to code business logic. 
Complete with mechanisms for transparently referencing (and accessing) 
data objects that currently don't reside in main memory (because e.g. 
they haven't been queried from the database yet, or they reside on some 
different server farm somewhere across the atlantic). Transaction-safe 
of course.


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 10:27:13
Message: <4f60aac1$1@news.povray.org>
Am 14.03.2012 10:43, schrieb Invisible:
> On 14/03/2012 05:48 AM, clipka wrote:
>
>> (For non-virtual classes it is good practice to define a protected
>> non-virtual destructor instead, just to be sure.)
>
> Is it wrong that whenever I read a sentence like this, I can hear a
> voice say "nuke it from space - it's the only way to be sure"?

Yeah, that would solve the problem, too :-P


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 10:36:42
Message: <4f60acfa$1@news.povray.org>
Am 14.03.2012 10:55, schrieb Invisible:

>> Note that the dispose is gone for good. Shared pointers use reference
>> counters to accomplish this feat.
>
> Every time I hear somebody say this, a part of me wants to scream "you
> /do/ understand that reference counting doesn't actually work, right?"

Which is because...?


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 10:38:21
Message: <4f60ad5d@news.povray.org>
On 14/03/2012 02:36 PM, clipka wrote:
> Am 14.03.2012 10:55, schrieb Invisible:
>
>>> Note that the dispose is gone for good. Shared pointers use reference
>>> counters to accomplish this feat.
>>
>> Every time I hear somebody say this, a part of me wants to scream "you
>> /do/ understand that reference counting doesn't actually work, right?"
>
> Which is because...?

Allow me to rephrase: Reference counting works if and only if the node 
reference graph is acyclic.

Sometimes it's feasible to ensure that this is the case. Sometimes it is 
not.


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:03:35
Message: <4f60b347$1@news.povray.org>
On 14/03/2012 02:15 PM, Warp wrote:
> Orchid Win7 v1<voi### [at] devnull>  wrote:
>> So 16 bytes of space overhead per node is worth it if you can avoid one
>> indirect jump instruction?
>
>    No, it's worth it if you can avoid one extraneous memory allocation
> (or having to manage the allocated memory manually).
>
>    A memory allocation will easily consume those 16 bytes of extra space
> anyways (the memory allocator bookkeeping, memory alignment, and the pointer
> used to refer to the allocated object), so it's not like you are gaining
> anything.

Heh, really? Most languages I work with can allocate new objects in O(1) 
time and using O(1) memory for bookkeeping. I'm not used to dynamic 
allocation being anything to worry about.

>> Mmm, I hadn't even thought of using an /array/. I suppose the upper
>> bound on the tree size is statically known, so why not?
>
>    The array doesn't necessarily have to be fixed in size.

It does if it's static. Either that or the source I'm reading is 
incorrect...

>    Calling a virtual function is in practice not any slower than calling
> a regular function.
>
>    Calling 'new', however, can be really slow (comparatively speaking).

Mmm, OK.

>    If you can reduce x millions of 'new' calls into eg. log(x millions) of
> 'new' calls, your program will probably become much faster.

Well, sure. If I was going to allocate, I don't know, one object for 
every pixel on the screen, then sure, I'd try to find a way to not do 
that dynamically. But for two-dozen objects of a few bytes each, I 
really wouldn't expect dynamic allocation to be a big deal. (Then again, 
I don't write C++ for a living...)

>> Out of curiosity, if /you/ were writing a piece of code that's supposed
>> to take a text string, parse it as an expression, and then execute the
>> resulting expression, how would you implement that?
>
>    You mean like this? http://warp.povusers.org/FunctionParser/

...I'd sit down and study that, but I'm guessing it's designed more for 
usability than readability.

>> The most obvious way
>> is to make every valid kind of expression be a different class, and have
>> an abstract base class with an "execute this" method, which gets
>> implemented differently for each type of expression.
>
>    If the parser consists of some dozens expression parsers which are added
> to the core module once at program start, then the slowness of memory
> allocation becomes completely irrelevant. You are not performing millions
> of 'new' operations, only a few dozen of them. The virtual function calls
> themselves are pretty efficient. (What you *should* avoid is calling 'new'
> and 'delete' during the parsing, if you want it to be as fast as possible.)

That was my feeling. The typical data sizes I'm working with are so 
minute that efficiency becomes almost moot. Even an exponential-time 
algorithm is pretty quick given small enough input. ;-)

>    The major design issue becomes the management of those dynamically
> allocated objects. (Smart pointers may be a good solution to this.)

Well, yes... I'm certainly not looking forward to tracking down memory 
management faults. :-/

>> OK, well, if there is a single TreeNode class, I could write something like
>
>>     TreeNode(TreeNode t0, TreeNode t1)
>>     {
>>       child0 = new TreeNode;
>>       child1 = new TreeNode;
>>       *child0 = t0;
>>       *child1 = t1;
>>     }
>
>    Since TreeNode there is managing dynamically allocated memory, you'll
> have to write a proper copy constructor and assignment operator or else
> you have a leak and/or accesses to deleted memory. (And as I said in my
> previous post, that's not trivial because of all the options you have.)

How about if I never actually need to duplicate the tree? Does that make 
things any simpler?

>> If, however, the TreeNode class is abstract, obviously this won't work
>> at all. I now need to know what the /actual/ type of t0 is before I can
>> allocate sufficient space for it.
>
>    Well, that's easy. You should do this:
>
>      class TreeNode
>      {
>       protected:
>          virtual TreeNode* clone() const = 0;
>
>       public:
>           TreeNode(const TreeNode&  t0, const TreeNode&  t1):
>               child0(t0.clone()),
>               child1(t1.clone())
>           {}
>
>           // Implement destructor, copy constructor and assignment
>           // operator appropriately here.
>      };
>
>    Then every inherited class implements that 'clone()' method like:
>
>      class FancyNode: public TreeNode
>      {
>       protected:
>          virtual TreeNode* clone() const
>          {
>              return new FancyNode(*this);
>          }
>      };

I definitely need to find a more thorough reading source; some of that 
syntax isn't even /explained/ on the site I read...

>> (I'm also fuzzy on what happens when
>> you try to delete a pointer - does it know what the "real" size of the
>> object is, or does it use the declared type of the pointer?)
>
>    If the pointer is handling a dynamically bound object, then the
> destructor of the base class has to be virtual. Then 'delete' is able
> to destroy the object appropriately.

Right. So as long as you remember to make the destructor virtual, it 
will look up the correct code from the vtable.


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:23:34
Message: <4f60b7f6@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> On 14/03/2012 02:15 PM, Warp wrote:
> > Orchid Win7 v1<voi### [at] devnull>  wrote:
> >> So 16 bytes of space overhead per node is worth it if you can avoid one
> >> indirect jump instruction?
> >
> >    No, it's worth it if you can avoid one extraneous memory allocation
> > (or having to manage the allocated memory manually).
> >
> >    A memory allocation will easily consume those 16 bytes of extra space
> > anyways (the memory allocator bookkeeping, memory alignment, and the pointer
> > used to refer to the allocated object), so it's not like you are gaining
> > anything.

> Heh, really? Most languages I work with can allocate new objects in O(1) 
> time and using O(1) memory for bookkeeping. I'm not used to dynamic 
> allocation being anything to worry about.

  Last time I checked, 16 bytes is O(1) memory.

> >> Mmm, I hadn't even thought of using an /array/. I suppose the upper
> >> bound on the tree size is statically known, so why not?
> >
> >    The array doesn't necessarily have to be fixed in size.

> It does if it's static. Either that or the source I'm reading is 
> incorrect...

  You don't have to use a static array.

> Well, sure. If I was going to allocate, I don't know, one object for 
> every pixel on the screen, then sure

  But that's exactly what object-oriented design would have you do.

  Anyways, the major issue with dynamic allocation is memory management.
If by avoiding allocating individual objects manually you save yourself
the trouble of having to manage the memory, it's a win-win situation.
Why would you not want to do that?

> >> OK, well, if there is a single TreeNode class, I could write something like
> >
> >>     TreeNode(TreeNode t0, TreeNode t1)
> >>     {
> >>       child0 = new TreeNode;
> >>       child1 = new TreeNode;
> >>       *child0 = t0;
> >>       *child1 = t1;
> >>     }
> >
> >    Since TreeNode there is managing dynamically allocated memory, you'll
> > have to write a proper copy constructor and assignment operator or else
> > you have a leak and/or accesses to deleted memory. (And as I said in my
> > previous post, that's not trivial because of all the options you have.)

> How about if I never actually need to duplicate the tree? Does that make 
> things any simpler?

  You are copying TreeNode objects in the above code. If you want to do that,
there's no way around it: You have to write a proper copy constructor and
assignment operator for the TreeNode class, else you'll have leaks and
bad accesses.

  What do you think "*child0 = t0" means?

-- 
                                                          - Warp


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:24:30
Message: <4f60b82e$1@news.povray.org>
Am 14.03.2012 10:55, schrieb Invisible:

>> There's nothing "incorrect" about that way of placing braces, even in
>> C++. It's syntactically correct, so say what you will.
>
> Writing the entire program in one source file on a single 435,235,342
> character line is "syntactically correct". But no sane programmer would
> ever do such a horrifying thing. :-P

And not every compiler need to support such a horrifying thing. 
(According to the C++ spec, the maximum number of characters per source 
line is up to the implementation, but the recommended minimum for that 
maximum is 65536.)

>> Anyway, I personally stick to IDEs developed by software development
>> companies (and I mean companies that develop other stuff besides
>> programming languages and IDEs). So far the best IDE experience has been
>> Visual Studio for C#. One might snarl at the company's marketing
>> strategies, but they seem to know what helps software developers to be
>> productive.
>
> I don't know about "what helps software developers to be productive"...
> How about "what makes software developers buy our product rather than
> somebody else's"? Or even "what makes software developers develop for
> our platform rather than somebody else's"? ;-)

Seriously, I'm pretty sure MS uses Visual Studio themselves in-house. In 
a serious number of seriously large projects. Knowing that every second 
a programmer is busy ranting about the development tools is one second 
that costs money.

> The entire MS business model fundamentally depends on getting everyone
> to use the MS platform, and then be locked in. Well, if your platform
> has naff-all software for it, nobody will buy it. But if your platform
> has all the best stuff, people will pay. And then be trapped. So it pays
> (literally) to make it easy for people to write code for your platform
> and only your platform. >:-D

While it is an open secret that MS' business model is centered on 
locking in their customers wherever they can, this approach of "make it 
easy for people to write software for your platform, and your platform 
will have the best software in existance" wouldn't fly: Making it easy 
for people to write code for your platform doesn't necessarily mean 
they'll produce /good/ software for it. You're also bound to get a lot 
of crap besides.

And then you'd also expect MS to give away VS for free (the real thing, 
with the tools to write the real powerful software, not just crappy 
hello world stuff), yet for some reason they don't.

I think there's another reason why VS is so good. I'm convinced they're 
not trying to make it easy for /anyone/ to write code - they're trying 
to make it easy for /themselves/. And make extra money by selling the 
toolset.


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:34:00
Message: <4f60ba68$1@news.povray.org>
>> Heh, really? Most languages I work with can allocate new objects in O(1)
>> time and using O(1) memory for bookkeeping. I'm not used to dynamic
>> allocation being anything to worry about.
>
>    Last time I checked, 16 bytes is O(1) memory.

You seem to suggest that there's 16 bytes of overhead /per object/. I'm 
saying I'm used to there being a fixed number of bytes of overhead, 
regardless of the number of objects. That's O(N) vs O(1).

>>>> Mmm, I hadn't even thought of using an /array/. I suppose the upper
>>>> bound on the tree size is statically known, so why not?
>>>
>>>     The array doesn't necessarily have to be fixed in size.
>
>> It does if it's static. Either that or the source I'm reading is
>> incorrect...
>
>    You don't have to use a static array.

Sure. But then you're dynamically allocating again.

>> Well, sure. If I was going to allocate, I don't know, one object for
>> every pixel on the screen, then sure
>
>    But that's exactly what object-oriented design would have you do.

Sure. And I'm saying, if I wanted to do something like that, then yes, I 
might go out of my way to try to make it efficient. (E.g., by not using 
elaborate inheritance hierarchies and such.)

>    Anyways, the major issue with dynamic allocation is memory management.
> If by avoiding allocating individual objects manually you save yourself
> the trouble of having to manage the memory, it's a win-win situation.
> Why would you not want to do that?

Sure, avoiding manual memory management is always a good idea. It seems 
the cost is that you have less flexibility in designing your classes. 
(Then again, how many different kinds of pixel can there possibly be?)

>>>     Since TreeNode there is managing dynamically allocated memory, you'll
>>> have to write a proper copy constructor and assignment operator or else
>>> you have a leak and/or accesses to deleted memory. (And as I said in my
>>> previous post, that's not trivial because of all the options you have.)
>
>> How about if I never actually need to duplicate the tree? Does that make
>> things any simpler?
>
>    You are copying TreeNode objects in the above code.

*facepalm*

Right. I think I know how to redesign to avoid that. Should make things 
a bit more coherent...


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:34:37
Message: <4f60ba8d$1@news.povray.org>
Am 14.03.2012 15:38, schrieb Invisible:
> On 14/03/2012 02:36 PM, clipka wrote:
>> Am 14.03.2012 10:55, schrieb Invisible:
>>
>>>> Note that the dispose is gone for good. Shared pointers use reference
>>>> counters to accomplish this feat.
>>>
>>> Every time I hear somebody say this, a part of me wants to scream "you
>>> /do/ understand that reference counting doesn't actually work, right?"
>>
>> Which is because...?
>
> Allow me to rephrase: Reference counting works if and only if the node
> reference graph is acyclic.
>
> Sometimes it's feasible to ensure that this is the case. Sometimes it is
> not.

While this is true, it is not a problem specific to reference counting, 
but one that is inherent in /any/ attempt at automatic object lifetime 
management.

That's why C++11 also provides weak pointers. They're not a cure-all for 
such problems, but they do help in some situations (such as when the 
cyclic references come from pointers to parent objects in a tree).


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:37:05
Message: <4f60bb21$1@news.povray.org>
> the recommended minimum for that maximum is 65536.

Irony...

> Seriously, I'm pretty sure MS uses Visual Studio themselves in-house. In
> a serious number of seriously large projects. Knowing that every second
> a programmer is busy ranting about the development tools is one second
> that costs money.

Well, yeah, there is that. If it's actually true...

> And then you'd also expect MS to give away VS for free (the real thing,
> with the tools to write the real powerful software, not just crappy
> hello world stuff), yet for some reason they don't.

Um... So how is the pro version actually different from VS Express?

> I think there's another reason why VS is so good. I'm convinced they're
> not trying to make it easy for /anyone/ to write code - they're trying
> to make it easy for /themselves/. And make extra money by selling the
> toolset.

Quite possibly. ;-)

Then again, Valve released their editing tools, and (from what I hear) 
they are really, really hard to use...


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:39:30
Message: <4f60bbb2$1@news.povray.org>
>> Allow me to rephrase: Reference counting works if and only if the node
>> reference graph is acyclic.
>>
>> Sometimes it's feasible to ensure that this is the case. Sometimes it is
>> not.
>
> While this is true, it is not a problem specific to reference counting,
> but one that is inherent in /any/ attempt at automatic object lifetime
> management.

And automatic garbage collection is the only general-purpose solution to 
this problem. Unfortunately, it's also very expensive (in time and often 
in space).

> That's why C++11 also provides weak pointers. They're not a cure-all for
> such problems, but they do help in some situations (such as when the
> cyclic references come from pointers to parent objects in a tree).

I'm not even sure what the semantics of a "weak pointer" would be in the 
absence of automatic memory management...


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:42:49
Message: <4f60bc79$1@news.povray.org>
Am 14.03.2012 10:42, schrieb Invisible:

> It seems either they implemented everything twice (once with, and once
> without generics), or it's actually legal to not specify type parameters
> and then they default to Object. Which, either way, is highly
> counter-intuitive...

It's actually that they /first/ implemented the stuff as non-generics 
(because Java didn't have them back then), and then added a generics 
implementation later when they discovered that generics were a good 
thing to have after all (retaining the old non-generics implementation 
for backward compatibility).


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:45:44
Message: <4f60bd28$1@news.povray.org>
On 14/03/2012 03:42 PM, clipka wrote:
> Am 14.03.2012 10:42, schrieb Invisible:
>
>> It seems either they implemented everything twice (once with, and once
>> without generics), or it's actually legal to not specify type parameters
>> and then they default to Object. Which, either way, is highly
>> counter-intuitive...
>
> It's actually that they /first/ implemented the stuff as non-generics
> (because Java didn't have them back then), and then added a generics
> implementation later when they discovered that generics were a good
> thing to have after all (retaining the old non-generics implementation
> for backward compatibility).

Backwards compatibility is pretty evil, eh? ;-)


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:50:18
Message: <4f60be3a@news.povray.org>
Invisible <voi### [at] devnull> wrote:
> >> Heh, really? Most languages I work with can allocate new objects in O(1)
> >> time and using O(1) memory for bookkeeping. I'm not used to dynamic
> >> allocation being anything to worry about.
> >
> >    Last time I checked, 16 bytes is O(1) memory.

> You seem to suggest that there's 16 bytes of overhead /per object/. I'm 
> saying I'm used to there being a fixed number of bytes of overhead, 
> regardless of the number of objects. That's O(N) vs O(1).

  That's obviously impossible. The only way to achieve that would be
to allocate an array of objects (by value).

  If you allocate individual objects, the allocator has to know where they
are and if those memory blocks are free or not. At least if the allocator
ever wants to reuse freed memory blocks.

> >>>> Mmm, I hadn't even thought of using an /array/. I suppose the upper
> >>>> bound on the tree size is statically known, so why not?
> >>>
> >>>     The array doesn't necessarily have to be fixed in size.
> >
> >> It does if it's static. Either that or the source I'm reading is
> >> incorrect...
> >
> >    You don't have to use a static array.

> Sure. But then you're dynamically allocating again.

  You are allocating *an array* dynamically, not individual objects.
You are making like a couple of 'news' rather than thousands or millions.

> Right. I think I know how to redesign to avoid that. Should make things 
> a bit more coherent...

  If you are creating a dynamic binary tree, there's no avoiding memory
allocation. (One of the very few cases where you can avoid it is with
things like a heap. While a heap is a dynamic binary tree, it can be
implemented as a single array rather than each object being allocated
separately. In fact, the C++ standard library offers heap creation and
managing functions.)

  A possible approach is that the nodes themselves do not manage the
objects they are pointing to, but rather the data container module
itself. This is, for example, what std::set does (in other words,
the nodes in a std::set do not manage the other objects they are
pointing to, but it's the std::set class itself that takes care of
allocating and deleting them as needed.) Of course this requires a
careful design as well, in order to avoid leaks or double deletions.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: A tale of two cities
Date: 14 Mar 2012 11:52:05
Message: <4f60bea4@news.povray.org>
clipka <ano### [at] anonymousorg> wrote:
> While this is true, it is not a problem specific to reference counting, 
> but one that is inherent in /any/ attempt at automatic object lifetime 
> management.

  It's not a problem for a garbage collector.

  And btw, cyclic references are not the only problematic situation with
reference counting. There are cases where objects may be deleted too early,
while there's still code using them.

-- 
                                                          - Warp


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 12:05:36
Message: <4f60c1d0@news.povray.org>
Am 14.03.2012 16:37, schrieb Invisible:

>> And then you'd also expect MS to give away VS for free (the real thing,
>> with the tools to write the real powerful software, not just crappy
>> hello world stuff), yet for some reason they don't.
>
> Um... So how is the pro version actually different from VS Express?

Last time I checked (though I must confess that's years ago) one 
difference was that the Express editions had quite limited flexibility 
regarding the project settings, to an extent that I didn't even bother 
trying them out further.

>> I think there's another reason why VS is so good. I'm convinced they're
>> not trying to make it easy for /anyone/ to write code - they're trying
>> to make it easy for /themselves/. And make extra money by selling the
>> toolset.
>
> Quite possibly. ;-)
>
> Then again, Valve released their editing tools, and (from what I hear)
> they are really, really hard to use...

Maybe that's because the development cycle in game engines is faster 
than that in general-purpose programming languages, so it wouldn't have 
paid off to develop better tools?

Remember that VS has been developed over how long now? Two decades?


Post a reply to this message

From: Invisible
Subject: Re: A tale of two cities
Date: 14 Mar 2012 12:07:59
Message: <4f60c25f$1@news.povray.org>
>> You seem to suggest that there's 16 bytes of overhead /per object/. I'm
>> saying I'm used to there being a fixed number of bytes of overhead,
>> regardless of the number of objects. That's O(N) vs O(1).
>
>    That's obviously impossible. The only way to achieve that would be
> to allocate an array of objects (by value).
>
>    If you allocate individual objects, the allocator has to know where they
> are and if those memory blocks are free or not. At least if the allocator
> ever wants to reuse freed memory blocks.

If you're using garbage collection, it's quite possible - and, indeed, 
usual. Each time the GC collects the garbage, it also defragments the 
free space. You therefore need only store a pointer to the next free 
byte of memory. To allocate, just increment this pointer by the size of 
the block allocated. Allocation is now O(1) in time and space.

What you're saying is that C++ (and any other language with manual 
memory management) can't do it this way, since there would be no way to 
move stuff around without breaking all the things trying to point to it. 
So free space becomes fragmented, and you start needing O(N) storage to 
keep track of it - and, presumably, O(N) to allocate and deallocate stuff...

>>>>>      The array doesn't necessarily have to be fixed in size.
>>>
>>>> It does if it's static.
>>>
>>>     You don't have to use a static array.
>
>> Sure. But then you're dynamically allocating again.
>
>    You are allocating *an array* dynamically, not individual objects.
> You are making like a couple of 'news' rather than thousands or millions.

Right, OK. You seem to be saying essentially the same thing as I am - 
dynamic allocation is OK, just try not to individually allocate millions 
of blocks.

>> Right. I think I know how to redesign to avoid that. Should make things
>> a bit more coherent...
>
>    If you are creating a dynamic binary tree, there's no avoiding memory
> allocation.

I meant, I think can avoid copying bits of tree around while I'm 
building the tree.

> (One of the very few cases where you can avoid it is with
> things like a heap. While a heap is a dynamic binary tree, it can be
> implemented as a single array rather than each object being allocated
> separately. In fact, the C++ standard library offers heap creation and
> managing functions.)

Yeah, I believe I've read about that. (Heaps in arrays, that is.) Which 
property of a heap is it that makes this possible?

>    A possible approach is that the nodes themselves do not manage the
> objects they are pointing to, but rather the data container module
> itself. This is, for example, what std::set does (in other words,
> the nodes in a std::set do not manage the other objects they are
> pointing to, but it's the std::set class itself that takes care of
> allocating and deleting them as needed.) Of course this requires a
> careful design as well, in order to avoid leaks or double deletions.

Yeah, with manual memory management, almost /everything/ requires 
careful thought and design. You want to make damned sure you know what 
you're trying to implement before you implement it...


Post a reply to this message

From: clipka
Subject: Re: A tale of two cities
Date: 14 Mar 2012 12:14:41
Message: <4f60c3f1$1@news.povray.org>
Am 14.03.2012 16:52, schrieb Warp:
> clipka<ano### [at] anonymousorg>  wrote:
>> While this is true, it is not a problem specific to reference counting,
>> but one that is inherent in /any/ attempt at automatic object lifetime
>> management.
>
>    It's not a problem for a garbage collector.

Last time I heard, reference counting /is/ a garbage collection mechanism.

>    And btw, cyclic references are not the only problematic situation with
> reference counting. There are cases where objects may be deleted too early,
> while there's still code using them.

I can't think of any reason why that could possibly happen, provided 
that the reference counting is implemented in a thread-safe manner.


Post a reply to this message

Goto Latest 50 Messages Next 50 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.