POV-Ray : Newsgroups : povray.off-topic : My first C++ program Server Time
4 Nov 2024 13:17:06 EST (-0500)
  My first C++ program (Message 91 to 100 of 149)  
<<< Previous 10 Messages Goto Latest 10 Messages Next 10 Messages >>>
From: Orchid XP v8
Subject: Re: A test
Date: 21 Sep 2008 04:43:06
Message: <48d6091a$1@news.povray.org>
Warp wrote:
> Orchid XP v8 <voi### [at] devnull> wrote:
>>      std::string  txt;
>>      std::cin  >> txt;
> 
>>      std::istringstream iss(txt);
>>      int number;
>>      iss >> number;
> 
>   I think you misunderstood the reason to use stringstreams.

Er, yeah, good point...

>>      if (number < target) {std::cout << "Too low."  << std::endl; continue;}
>>      if (number > target) {std::cout << "Too high." << std::endl; continue;}
>>      break;
> 
>   Wouldn't it be simpler to do it like:
> 
>     if(number == target) break;
>     if(number < target) std::cout << "Too low.\n";
>     else std::cout << "Too high.\n";

Mmm, I guess that would also work...

-- 
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*


Post a reply to this message

From: Warp
Subject: Re: A test
Date: 21 Sep 2008 04:56:28
Message: <48d60c3c@news.povray.org>
Darren New <dne### [at] sanrrcom> wrote:
> Warp wrote:
> >     case(compare(number, target)) of
> >   What would be wrong with a syntax like that?

> All the functions in Haskell are curried. So it's really
>    case (compare(number)(target)) of ...

  How does Haskell distinguish where a nested (possibly curried) function
call ends, and the outer one continues? Assume that you would want to
write (here in C++ style) something like:

    foo(a, bar(b, c), d, e)

  If you wrote that as a Haskell-style no-delimiters function call,
I suppose it would look like:

    foo a bar b c d e

  Exactly how does Haskell decide how many parameters 'bar' takes there
(and consequently how many of the rest of the parameters are for 'foo')?

  I can't even begin to imagine how you would write that using the
"point syntax", seen in many examples posted by Andrew. Perhaps you
use parentheses to enclose the 'bar' call?

  (Btw, I think this demonstrates one problem with Haskell. I'm an
experienced programmer, and I do have a moderate understanding of the
functional paradigm, and I have been seeing quite many example programs
posted by Andrew during the last years. Yet I'm still completely unable
to figure out or deduce how you could write that in Haskell. It must be
simple, but I just don't know, even though I have seen many examples of
small Haskell programs.
  There just is something about the Haskell paradigm and syntax that
makes it confusing and hard to assimilate.)

-- 
                                                          - Warp


Post a reply to this message

From: Orchid XP v8
Subject: Re: A test
Date: 21 Sep 2008 05:29:04
Message: <48d613e0$1@news.povray.org>
Warp wrote:

>   How does Haskell distinguish where a nested (possibly curried) function
> call ends, and the outer one continues? Assume that you would want to
> write (here in C++ style) something like:
> 
>     foo(a, bar(b, c), d, e)
> 
>   If you wrote that as a Haskell-style no-delimiters function call,
> I suppose it would look like:
> 
>     foo a bar b c d e
> 
>   Exactly how does Haskell decide how many parameters 'bar' takes there
> (and consequently how many of the rest of the parameters are for 'foo')?

You'd have to throw in some brackets to disambiguate.

If you change every "foo(x, y, z)" into "(foo x y z)", you'll get a 
valid expression. In this case, we have

   foo a (bar b c) d e

If you wrap the whole thing in brackets, then the following rule 
applies: the first token after each "(" is the function being called; 
everything else is arguments.

What may be a little confusing is that a function's arguments may be 
functions themselves - even standard library functions. This is very 
useful from a programming perspective (indeed, the whole paradigm is 
based on it), but perhaps rather unhelpful for anybody trying to read 
the thing.

Where this starts to go wrong is where you start using operators. 
Obviously "2 + 7" means... well... two plus seven. It would be tedious 
(though perhaps more consistent) to write this as "(+) 2 7".

To understand how to parse an expression involving operators, you must 
know (or take a reasonable stab at) operator precidences. For arithmetic 
operators, it's the usual stuff. Function application has a higher 
precidence than anything else in the language - so "foo x + bar y" 
parses as "(foo x) + (bar y)" and not "foo (x + bar) y".

And that leads us neatly on to...

>   I can't even begin to imagine how you would write that using the
> "point syntax", seen in many examples posted by Andrew.

You can't. Because the nested expression isn't the final argument in the 
argument list. (Haskell programmers are very fussy about what order to 
put function arguments in for just this reason.)

>   (Btw, I think this demonstrates one problem with Haskell. I'm an
> experienced programmer, and I do have a moderate understanding of the
> functional paradigm, and I have been seeing quite many example programs
> posted by Andrew during the last years. Yet I'm still completely unable
> to figure out or deduce how you could write that in Haskell. It must be
> simple, but I just don't know, even though I have seen many examples of
> small Haskell programs.
>   There just is something about the Haskell paradigm and syntax that
> makes it confusing and hard to assimilate.)

The following are all equivilent:

   function1 (function2 (function3 (function4 (function5 x))))

   function1 $ function2 $ function3 $ function4 $ function5 $ x

   function1 $ function2 $ function3 $ function4 $ function5 x

   (function1 . function2 . function3 . function4 . function5) x

The last one creates a function by chaining several functions together, 
and then passes x as the argument to that function. Normally you 
wouldn't do that; you'd only use (.) if you wanted to pass a function as 
an argument or something:

   map (reverse . toUpper)

(Takes a list of strings, converts each string to upper case, and then 
reverses it.)

Where this starts to get crazy is if you have functions that take more 
than one argument. Because functions are curried, you may write

   function2args x $ function4args a b c $ function1arg j

or something.



So, between recognising language keywords, bracketed expressions, ($) 
and (.), and infix operators, I guess there *is* quite a bit to be 
getting on with.

It's interesting to me that most people seem confused not by curried 
functions or monads or high-order functions, but by the basics of 
parsing Haskell's syntax. I guess I'm so used to it be now that I take 
it for granted - but obviously, if you can't read the language syntax, 
you don't stand much chance of getting very far. I'll go have a think 
about that...

-- 
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*


Post a reply to this message

From: Warp
Subject: Re: My first C++ program
Date: 21 Sep 2008 07:21:26
Message: <48d62e33@news.povray.org>
Warp <war### [at] tagpovrayorg> wrote:
>   What you can do is this:

>     std::string s;
>     while(true)
>     {
>         std::cin >> s;
>         if(!std::cin.good()) break;

>         int value;
>         std::istringstream iss(s);
>         iss >> value;
>         if(!iss.fail())
>             std::cout << "The input was an integer: " << value << "\n";
>         else
>             std::cout << "The input was something else: " << s << "\n";
>     }

  Actually there is a way to achieve the same thing with std::cin
directly, without having to use stringstreams.

  If an input stream fails to read data which fits the parameter type,
it will stop reading, so anything that was in the input (which was not
whitespace) will be left there. It's thus possible to check if reading
the integer filed, and if it did, read it as a string.
  The only catch is that you have to clear the error flags of std::cin
before you can continue reading properly.

  The above example code can thus be written as:

    while(true)
    {
        int value;
        std::cin >> value; // Try to read an integer
        if(std::cin.fail()) // If there was no integer in the input
        {
            std::cin.clear(); // Clear the error flags
            std::string s;
            std::cin >> s; // Read a string
            if(!std::cin.good()) break;
            std::cout << "The input was something else: " << s << "\n";
        }
        else
        {
            std::cout << "The input was an integer: " << value << "\n";
        }
    }

  Thus removing the need for stringstreams.

-- 
                                                          - Warp


Post a reply to this message

From: Orchid XP v8
Subject: Re: My first C++ program
Date: 21 Sep 2008 07:32:00
Message: <48d630b0$1@news.povray.org>
Warp wrote:

>   Actually there is a way to achieve the same thing with std::cin
> directly, without having to use stringstreams.
> 
>   If an input stream fails to read data which fits the parameter type,
> it will stop reading, so anything that was in the input (which was not
> whitespace) will be left there. It's thus possible to check if reading
> the integer filed, and if it did, read it as a string.
>   The only catch is that you have to clear the error flags of std::cin
> before you can continue reading properly.

Thanks for the tip.



By the way... what's the usual C++ idiom for handling failure?

In Haskell, if you have some function that could fail for some reason, 
you have two options:

1. Throw an exception if there's a problem. (Only I/O code can catch and 
handle exceptions.)

2. Use the "maybe" datatype, which contains either some data, or a 
"there's nothing here" flag. (And because the type is different, the 
caller *must* explicitly check which it is before using the result for 
anything.)

Typically you throw an exception for something like "we ran out of 
memory" or "you called with an invalid argument". But for something 
like, say, looking up a key in a dictionary, it's a very predictable 
thing that the key might not actually exist, so the "maybe" approach is 
used there.

What is the "usual" C++ style for this kind of thing? (I'm asking a 
question of style here; clearly there are several possible things you 
*could* do in C++.)

-- 
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*


Post a reply to this message

From: Warp
Subject: Re: My first C++ program
Date: 21 Sep 2008 07:53:44
Message: <48d635c6@news.povray.org>
Orchid XP v8 <voi### [at] devnull> wrote:
> What is the "usual" C++ style for this kind of thing? (I'm asking a 
> question of style here; clearly there are several possible things you 
> *could* do in C++.)

  The standard data containers, as well as 'new', throw an exception by
default when they run out of memory. Also the at() member function of
some of the containers throws an exception if you try to index out of
boundaries.

  If you don't want to throw exceptions in your own code, then it depends
on what is it that you want to do to signal a condition.

  The usual way to catch programming errors at runtime is to use
assertions. For example:

void foo(int min, int max)
{
    assert(min <= max);

    // rest of the code here
}

  If the assertion fails, a message will be printed and the program is
immediately terminated at that point. Obviously this should only be
used in situations which are a symptom of a programming error and which
must be fixed.

  (The good thing about assert() is that you can freely use it as much
as you want. In fact, the more you use it, the better. You can compile
the program with a special precompiler parameter which will remove all
the asserts from the executable so that they will not add overhead to
a final version.)

-- 
                                                          - Warp


Post a reply to this message

From: Orchid XP v8
Subject: Re: My first C++ program
Date: 21 Sep 2008 08:06:18
Message: <48d638ba$1@news.povray.org>
Warp wrote:

>   The standard data containers, as well as 'new', throw an exception by
> default when they run out of memory. Also the at() member function of
> some of the containers throws an exception if you try to index out of
> boundaries.
> 
>   If you don't want to throw exceptions in your own code, then it depends
> on what is it that you want to do to signal a condition.
> 
>   The usual way to catch programming errors at runtime is to use
> assertions. For example:
> 
> void foo(int min, int max)
> {
>     assert(min <= max);
> 
>     // rest of the code here
> }
> 
>   If the assertion fails, a message will be printed and the program is
> immediately terminated at that point. Obviously this should only be
> used in situations which are a symptom of a programming error and which
> must be fixed.

Right. So assert() is for stuff that should never happen if the 
programmer is doing their job right. In other words, BUGS.

How about stuff that might ordinarily be expected to not work? E.g., 
parsing strings, looking up keys in dictionaries, etc.

It seems that streams at least signal errors by altering the stream 
object and getting the programmer to call a member function to check 
whether an error condition occurred. Is that a usual C++ idiom?

-- 
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*


Post a reply to this message

From: Warp
Subject: Re: My first C++ program
Date: 21 Sep 2008 08:18:51
Message: <48d63bab@news.povray.org>
Orchid XP v8 <voi### [at] devnull> wrote:
> It seems that streams at least signal errors by altering the stream 
> object and getting the programmer to call a member function to check 
> whether an error condition occurred. Is that a usual C++ idiom?

  I'm not sure there *is* any "usual" C++ idiom for error handling
(other than throwing exceptions).

-- 
                                                          - Warp


Post a reply to this message

From: Darren New
Subject: Re: (And in Haskell. Obviously.)
Date: 21 Sep 2008 10:09:31
Message: <48d6559b$1@news.povray.org>
Orchid XP v8 wrote:
> Both C and C++ are positively *bursting* with features that are subtle, 
> counter-intuitive and cryptic.

No, actually, C is really, really straightforward. Almost moreso than 
assembler. It's not subtle and complex and cryptic. It's just difficult 
and tedious.

> This isn't exactly news. C++ at least 
> appears to be something of an improvement in this regard...

I, personally, think C++ has many features that seem subtle and 
counter-intuitive, as evidenced by the fact that it's really hard to 
explain how some of the features work and when they come into play. Most 
people seem to say "this is how you use them" without actually knowing 
why using them that way actually works.  (Granted, I don't have a whole 
lot of experience with C++, so I probably sound way off base to those 
who know C++ well.)

-- 
Darren New / San Diego, CA, USA (PST)


Post a reply to this message

From: Darren New
Subject: Re: A test
Date: 21 Sep 2008 10:20:41
Message: <48d65839$1@news.povray.org>
Warp wrote:
>     foo(a, bar(b, c), d, e)
> 
>   If you wrote that as a Haskell-style no-delimiters function call,
> I suppose it would look like:
> 
>     foo a bar b c d e

>   Exactly how does Haskell decide how many parameters 'bar' takes there
> (and consequently how many of the rest of the parameters are for 'foo')?

It's curried. Each function only takes one.

In your example, I'm pretty certain you *have* to have parens.

foo a (bar b c) d e

>   I can't even begin to imagine how you would write that using the
> "point syntax", seen in many examples posted by Andrew. Perhaps you
> use parentheses to enclose the 'bar' call?

Hmmmm. I don't know you can do it with "point syntax" either. I think 
the a . b . c syntax only works when the result of "c" is the one and 
only argument to "b", and the result of "b" is the one and only argument 
to "a".

So if you wanted a function that returns the sum of the lengths of a 
list of strings, you might write
     length . concat
or something, if "concat" was a function that took a list of strings and 
returned their concatenation.

>   There just is something about the Haskell paradigm and syntax that
> makes it confusing and hard to assimilate.

I think most of the powerful languages have syntax that's confusing and 
hard to assimilate. C and C++ are also very confusing in syntax. (For 
example, I can barely follow the reference-counting pointer code you 
posted, and that only because I am only trying to read it and not write 
it. :-)

Even Tcl, which has exactly 12 rules of syntax, winds up being confusing 
to newbies because it's *too* simple. LISP has too many parentheses, 
even tho the grammar is about 3 lines of BNF.

About the only languages that aren't confusing are the weak ones: BASIC, 
Pascal, etc.

If the language is powerful because it does a lot (like Ada or C++) you 
wind up with lots and lots of syntax and lots of rules about the 
interactions. If the language is powerful because it's simple and 
regular (like LISP or FORTH or Tcl or Haskell) then it's confusing 
because there's no *obvious* way to accomplish the powerful stuff you 
know the language is capable of. (Sort of like Go or Chess or something 
- simple rules but very unobvious combinations.)

-- 
Darren New / San Diego, CA, USA (PST)


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.