POV-Ray : Newsgroups : povray.off-topic : Standard libraries Server Time
9 Oct 2024 21:18:37 EDT (-0400)
  Standard libraries (Message 71 to 80 of 108)  
<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>
From: Nicolas Alvarez
Subject: Re: Standard libraries
Date: 7 Mar 2009 17:52:37
Message: <49b2fab5@news.povray.org>
Darren New wrote:
> Warp wrote:
>>   Another example: You could give std::sort() a comparator as a lambda
>> function which has access to the variables in the local scope, something
>> which is very laborious to do currently.
> 
> Hmmm. OK, thanks. I can see where something like that could be convenient.
> Most places I've seen that need that sort of thing pass in a "client data"
> sort of opaque pointer to allow it, so I guess this new stuff could
> obviate the need to design that in at the application layer.

In C, the standard qsort() function takes a function pointer and (I think)
a "client data" void pointer. You have to put your state in a struct, send
the pointer as client data, then in your comparator function get the data
through the pointer.

In C++, the standard std::sort template function takes a comparator functor.
Using functors (which can be an instance of a stateful class, or can be a
plain old function) instead of passing a "client data" pointer is quite
common in C++.

Here is a [useless in practice] example where the comparator takes an
initialization parameter (whether to sort descending or ascending), and
also keeps state that can be retrieved later (how many times the comparison
function was called).

struct MyComparator {
    bool reverse_mode;
    int comparison_count;

    MyComparator(bool reverse) {
        reverse_mode = reverse;
        comparison_count = 0;
    }

    bool operator()(int a, int b) {
        comparison_count++;
        if (reverse_mode) {
            return b < a;
        } else {
            return a < b;
        }
    }
};

std::vector<int> list;

MyComparator c(false);
std::sort(list.begin(), list.end(), c);

cout << "Comparator called " << c.comparison_count << " times\n";

If you don't need to retrieve any data after the comparison, you could also
do this:

std::sort(list.begin(), list.end(), MyComparator(false));


With lambdas, you can use "closures" to keep state, so you don't need a
separate class/struct declared elsewhere:

std::vector<int> list;
int comparison_count=0;

std::sort(list.begin(), list.end(), [&comparison_count](int a, int b) {
    comparison_count++;
    return a < b;
});

Even if you don't want to keep any state (and leave the [] empty to use no
closures), it's still useful to declare the comparison code right next to
the std::sort call, instead of in a function/class possibly far away in
the .cpp file. This is the part I said was similar to string literals (you
know how in assembler you need a manually-made list of strings at the
beginning of the program? :P).


Post a reply to this message

From: Warp
Subject: Re: Standard libraries
Date: 7 Mar 2009 17:55:44
Message: <49b2fb70@news.povray.org>
Nicolas Alvarez <nic### [at] gmailcom> wrote:
> for (std::vector<int>::const_iterator i = someList.begin(); i !=
> someList.end(); ++i) {
>     total += *i;
> }

  Maybe not the best of examples because with the next C++ standard you
will also be able to do it like:

    for(auto i = someList.begin(); i != someList.end(); ++i)
        total += *i;

which is not enormously longer than the lambda version.

-- 
                                                          - Warp


Post a reply to this message

From: Nicolas Alvarez
Subject: Re: Standard libraries
Date: 7 Mar 2009 17:58:49
Message: <49b2fc29@news.povray.org>
Warp wrote:
> Nicolas Alvarez <nic### [at] gmailcom> wrote:
>> for (std::vector<int>::const_iterator i = someList.begin(); i !=
>> someList.end(); ++i) {
>>     total += *i;
>> }
> 
>   Maybe not the best of examples because with the next C++ standard you
> will also be able to do it like:
> 
>     for(auto i = someList.begin(); i != someList.end(); ++i)
>         total += *i;
> 
> which is not enormously longer than the lambda version.

Yes, when changing C++ code to C++0x, I'll have to decide which of the two
types of awesome to use.


Post a reply to this message

From: Darren New
Subject: Re: Standard libraries
Date: 7 Mar 2009 20:19:43
Message: <49b31d2f$1@news.povray.org>
Warp wrote:
>   However, it doesn't matter! As long as F behaves like a function, that's
> just fine. This is used quite a lot in template coding, eg. with functors
> and comparators. This gives flexibility and versatility.

Hmm. I never thought of it that way. OK.

>   It's not like C++ was the only language which behaves like this.

Well.... I think it's one of the few languages where you can't tell whether 
something's invoking a function or adding a name to the namespace at compile 
time.  It would seem to make writing parsers and such harder than it needs 
to be.

I'll grant that there are a number of languages where (say) writing "F(5)" 
doesn't tell you whether F is a function, a pointer to a function, or a 
function that returns another function, say.

>   Most languages have special keywords to denote what you want to do.
> For example, some languages might have a keyword like "function" to denote
> that you are starting a function definition, as opposed to starting a
> function call. I don't really see the big difference.

It makes the grammar easier to automate.

>> You can't tell me a language with undecidable syntax isn't at least a little 
>> sucky, yes?
> 
>   When that syntax brings flexibility, I don't consider is such a huge
> problem.

Other languages seem to manage being as flexible without having such complex 
grammars. I'll grant that they trade off runtime efficiency to achieve that.

-- 
   Darren New, San Diego CA, USA (PST)
   My fortune cookie said, "You will soon be
   unable to read this, even at arm's length."


Post a reply to this message

From: Darren New
Subject: Re: Standard libraries
Date: 7 Mar 2009 20:31:38
Message: <49b31ffa$1@news.povray.org>
Nicolas Alvarez wrote:
> This is the part I said was similar to string literals (you
> know how in assembler you need a manually-made list of strings at the
> beginning of the program? :P).

Oh! OK.  I had no idea that's what you were talking about, and I thought you 
were comparing lambda expressions to string literals somehow.

Thanks for the excellent examples.

-- 
   Darren New, San Diego CA, USA (PST)
   My fortune cookie said, "You will soon be
   unable to read this, even at arm's length."


Post a reply to this message

From: Warp
Subject: Re: Standard libraries
Date: 7 Mar 2009 20:34:13
Message: <49b32095@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Well.... I think it's one of the few languages where you can't tell whether 
> something's invoking a function or adding a name to the namespace at compile 
> time.  It would seem to make writing parsers and such harder than it needs 
> to be.

  Who cares if writing a parser is harder? Programs are supposed to help
people, not the other way around. I prefer latex over xml any day, even
though creating a latex parser is way more complicated than creating an
xml parser.

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: Standard libraries
Date: 7 Mar 2009 23:29:42
Message: <49b349b6$1@news.povray.org>
Warp wrote:
>   Who cares if writing a parser is harder? 

Well, anyone implementing compilers or interpreters for one. If the compiler 
gave you runtime type information sufficient for everyone's needs, that 
would probably be enough. But if you want to (say) write something that'll 
take a structure and store it in database tables, or serialize something to 
a file or a SOAP message or some such, not having the type information *and* 
not being able to easily parse the header files can be problematic.

-- 
   Darren New, San Diego CA, USA (PST)
   My fortune cookie said, "You will soon be
   unable to read this, even at arm's length."


Post a reply to this message

From: Darren New
Subject: Re: Standard libraries
Date: 8 Mar 2009 00:09:20
Message: <49b35300$1@news.povray.org>
Warp wrote:
>   You still know that I get trolled when someone writes such mocking words
> about C++ as you have done.

You know, I took a couple hours away, then went back and looked at what I'd 
typed. I think if you look at my initial posts here objectively, you'll see 
they weren't mocking, as almost all of it was asking questions about the 
implementation.

What I failed to do was describe the mental process that caused me to ask 
the kinds of apparently-silly questions I was asking. I thought

(( Wow, C++ is getting lambdas. I guess they're standardizing Boost, which 
is ugly. )) "I bet it'll be ugly."

(( No, it actually *looks* not too bad. But I wonder how they implement it, 
then. That's a mess behind the scenes in C#, and in pretty much every 
language I know that keeps variables on the machine stack, so I wonder how 
they're doing closures. I wonder how the closed-over variables survive the 
destruction of the stack frame. ))

"Can you return lambda values from a function?"  (( Because if not, then you 
don't have to worry about the stack frame not being there. Oh, but I'm told 
you can. Cool. Maybe it's going to copy the values from the stack into a 
heap-allocated object. But how would it GC the heap-allocated object, if 
multiple lambdas point to it? Maybe it's doing reference counting. But that 
doesn't work, if you get circular references, which you can't get if you 
can't assign to a variable except a new variable. ))

"Can you assign it to a variable?"  (( Oh, you can do that too. Wow, that's 
really impressive. I can't imagine what they're doing to make closures work.))

"Thanks for the link to wikipedia."  (( Oh, wikipedia says you just randomly 
get hosed if you try to actually use values you thought you closed over when 
you created the lambda, unlike every other language that ever implemented 
the feature called 'lambda expressions'. ))

"Gee, C++ lambdas sure suck compared to everyone else's that actually 
manages to create a closure from lambdas."  (( I wonder what it could be 
useful for, since I can't think of a reason I'd use a lambda that I couldn't 
return from the function in which I created it. ))

"Why not just use a for loop?"  (( Oh, I see. I wasn't thinking like that, 
because I was still thinking in terms of lambdas rather than in terms of 
downward funargs. ))

I can see how if I didn't make clear why I was asking the questions, you 
might leap to the conclusion (perhaps justifiably) that I was simply looking 
for the flaws in order to criticize C++.  In reality, I was looking for the 
flaw in my mental model of how C++ handles memory that would allow the 
memory for the closure to be collected only after the lambda has been 
collected. Or, given that I'm pretty sure I understand how C++ works its 
memory model, I was looking for the cool impressive clever mechanism that 
would let the closure get allocated in a way that would work.

-- 
   Darren New, San Diego CA, USA (PST)
   My fortune cookie said, "You will soon be
   unable to read this, even at arm's length."


Post a reply to this message

From: Darren New
Subject: Re: Standard libraries
Date: 8 Mar 2009 00:09:21
Message: <49b35301$1@news.povray.org>
Nicolas Alvarez wrote:
> Darren New wrote:
>> I can pass you a void* and
> 
> That's a C feature. Real C++ programmers don't use void*. So no, of course
> you have no RTTI on a void*.

OK. What am I doing wrong here, that I'm not getting the size of the actual 
instance passed in?

#include <iostream>

class Alpha {
   public:
   int i;
   Alpha() { i = 9; }
   virtual ~Alpha() { }
   virtual int yidda() { return 0; }
   virtual int mysize() { return sizeof(*this); }
};

class Beta : public Alpha {
   public:
   long l0, l1, l2, l3, l4, l5, l6, l7;
   Beta() { i = 10; }
   virtual ~Beta() { }
   virtual int yidda() { return 1; }
};

void show_size(Alpha & xyz) {
   std::cout << sizeof(xyz) << std::endl;
   std::cout << xyz.mysize << std::endl;
}

int main() {
   Alpha alpha;
   Beta  beta;
   show_size(alpha);
   show_size(beta);
   return 0;
}

Why does this print "8 8 8 8"? If there's RTTI, shouldn't I at least be able 
to figure out how big my structure is without having to code a function to 
calculate it for every function?  Seriously, if you wanted to write whatever 
structure "show_size" got passed out to a file, how would you do it? Would 
you have to write a "return sizeof(*this)" in each and every class as a 
virtual function? A function inherited by the parent into the child doesn't 
know that "this" is pointing to a child type?  (I tried adding more longs to 
alpha and I started getting 32's, so it's not giving me the size of the 
reference itself.)

If I copy the text of mysize() into Beta's class, mysize() returns 40 for 
betas. That seems kind of ... not right, to me. I duplicate a virtual 
function into a child class without changing it, and it gives different 
answers than if I inherited it?

>> The traceback in your exceptions
>> can tell you what the values passed as arguments to the function on each
>> frame...
> 
> Yes they can.

I wasn't aware C++ even defined tracebacks on exceptions. How does one 
access that feature? The googles with the obvious words mostly talk about 
python exceptions passing through C++, and the g++ exception.h file declares 
exception as having a constructor, destructor, and a "what" field, but no 
traceback. What should I google on to find the right invocation to get the 
traceback out of an exception?

>> Hell, you can't even tell me how big an array is
> No, but you'll see me using std::vector, not arrays, in C++.

Yes, because you can't see how big an array is.

>> I know how it *won't* be implemented. It won't be implemented such that
>> references to local variables survive the end of the stack frame those
>> local variables are allocated in. That's enough.
> 
> They never do,

Well, no, not in C++. That's kind of my point. In other languages with 
lambdas, yes, they do. That's why it's called a closure. That's why I was 
asking stupid questions about how C++ manages to do that. :-)

> And in my mind it wouldn't be a stack if it kept
> alive after 'popped' :D

Well, yes. That's exactly why I'm asking "Wow, how does C++ do that??" 
Because, like, that's what "lambda" means, and C++ can't do it, so I'm 
trying to figure out what amazing mechanism they used.

-- 
   Darren New, San Diego CA, USA (PST)
   My fortune cookie said, "You will soon be
   unable to read this, even at arm's length."


Post a reply to this message

From: Warp
Subject: Re: Standard libraries
Date: 8 Mar 2009 12:03:02
Message: <49b3ec36@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> OK. What am I doing wrong here, that I'm not getting the size of the actual 
> instance passed in?

[snip]

> Why does this print "8 8 8 8"? If there's RTTI, shouldn't I at least be able 
> to figure out how big my structure is without having to code a function to 
> calculate it for every function?

  The problem is that sizeof() is a static construct which is evaluated at
compile time, not something evaluated at runtime. sizeof() in particular
does *not* take into accout RTTI. When you say "sizeof(*this)" (in your
example), that's by standard specification exactly identical to
"sizeof(Alpha)".

  But C++ does have RTTI. For example try this:


#include <iostream>
#include <string>
#include <typeinfo>

class Alpha
{
 public:
    virtual ~Alpha() {}
    std::string myType() const { return typeid(*this).name(); }
};

class Beta: public Alpha
{
};

int main()
{
    Alpha obj1;
    Beta obj2;
    Alpha& obj3 = obj2;

    std::cout << obj1.myType() << " "
              << obj2.myType() << " "
              << obj3.myType() << std::endl;
}


  Even though the class Alpha does not see the class Beta in any way (you
could make completely sure of that by putting them in different compilation
units), it will still return the correct typeid name depending on whether
the object is really of type Alpha or of type Beta.

-- 
                                                          - Warp


Post a reply to this message

<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>

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