From: Matthew Heaney <matthew_heaney@acm.org>
Subject: Re: Weird get_line()
Date: 1999/03/30
Date: 1999-03-30T00:00:00+00:00 [thread overview]
Message-ID: <m37lrzu3ao.fsf@mheaney.ni.net> (raw)
In-Reply-To: yam7758.1500.1147822784@post.demon.co.uk
W1bBle <layabouts@the-giant-sofa.demon.co.uk> writes:
> >Using Get_Line will ensure that all characters are consumed, including
> >the line terminator.
> >
>
> Yeah, that's exactly what I suspected was happening. Forgive me for
> saying this, but don't you think that because of this the above code
> being necessary makes the whole solution less elegant?
No, because you're doing something inherently low-level (I/O).
If you want something else, you could try playing around with
Get_Immediate.
> >So just always use Get_Line, and don't bother with Get.
> >
>
> So what was get() designed for? If get_line() was for handling strings
> in a competent manner, why even /have/ get() in the first place?
Because sometimes you'll want to consume a character at a time.
Realize that Text_IO is for reading characters from a file and for
reading characters from a human. If you're reading from a file, you may
need to read one character at a time, and Get is fine for that.
But for reading characters entered by a human user on standard input, it
has been my experience that using Get_Line is simpler. Idioms for
interaction with a human user are different from the idioms for reading
characters out of a file.
> >Get didn't see the line terminator, because it came _after_ the
> >character.
>
> Ahem. How does get know when you have finished giving it input if you
> don't put in a line terminator?
That's an implementation issue. The terminal driver delivers the buffer
when you press return, and you're using Get to read characters out of
the buffer one at a time.
The alternative is to read the characters all at once, by using
Get_Line.
Another possibility is to use Get_Immediate.
It has been my experience that for reading text input from a user, the
simplest thing is just use Get_Line for the I/O part (to move the input
buffer from standard input to the application), and then interrogate the
buffer myself, as a separate step.
> >Yes, it is a feature. And yes, it does make sense. Get only consumes a
> >line terminator if it sees one _before_ the next non-control character.
>
> Pardon???!!! Assuming the input stream hasn't been loaded (under a
> true unix system) with data from a pipe, and stdin is looking at the
> keyboard device (or any other, slow, serial input device, if you see
> what I mean...) then how will it know the character that it is
> checking at a moment in time, which in this case could be line
> terminator, say, is followed by another non control character?
I'm not sure I understand your question. The invocation
Get (C);
won't complete until the user enters a non-control character. You can
hit the <return> key all you want, but until you enter a non-control
character, Get won't complete.
Try it:
with Text_IO; use Text_IO;
procedure Test_Get is
C : Character;
begin
Get (C);
end;
> >You can read all about Text_IO in section A.10 of your handy-dandy
> >reference manual.
> >
>
> Do you mean that impenetrable, indecipherable heap of ascii that Ada
> home has a link to?
A.10 isn't all that bad. At some point you're going to have to
familiarize yourself with the RM.
> >If you want an operation to fetch a char and the line terminator that
> >_follows_ it, then use Get_Line.
>
> But what if it is a number to be loaded into a variable? Do you really
> want to write a whole chunk of code to parse a string, figure out (bad
> pun) that you have a number, and then shove it in the variable? Did m$
> have a hand in developing this...? ;)
No. All I'm saying is to use Get_Line as a means of doing the I/O, to
move the input line from the terminal to the application.
When you get the line, then you use other mechanisms to convert the
string buffer to a number.
To convert a string to a value, you can use T'Value:
declare
Value : constant Integer := Integer'Value (Line (1 .. Last);
begin
or use:
Get (From : in String;
Item : out Num;
Last : out Positive);
as in
declare
Value : Integer;
Last : Positive;
begin
Get (From => Line (1 .. Last), Item => Value, Last => Last);
end;
The first method will raise Constraint_Error if the text isn't a number,
the second method will raise Data_Error.
No, you don't have to write string parsing algorithms yourself. That
wasn't what I was advocating.
There are other Get operations:
Get (Item : out Num;
Width : in Field := 0);
that combine the two steps, consuming some of the characters from the
terminal, checking that the lexeme forms a valid number, and then doing
the conversion.
I prefer a two-step approach:
1) use Get_Line to move the data to the app
2) use T'Value or Get (From : in String; ...) to convert the string to a
number
The problem with the other approach is that you have to do a Skip_Line
anyway, because Get (Item : out Num; ...) doesn't consume the
end-of-line.
So you might as well just use Get_Line, which does the Skip_Line
automatically.
> >My advice to you and everyone else is to always first use Get_Line to
> >transfer characters from standard input, and then internally vet and
> >parse the character string.
> >
> >Don't bother with Get, Skip_Line, Integer_IO.Get, Float_IO.Get, etc.
> >Just use Get_Line.
>
> Phwar! Like I said, a lot of work for such a simple task. Or so it
> seems to me at least.
I think there is a misunderstanding, because the task is not that hard.
I meant,
Don't use the Get (Item : out Num; ...) operations.
I also meant,
Do use
Get_Line (Line, Last);
Get (Line (1 .. Last), Item, Last);
or do use
Get_Line (Line, Last);
Item := I'Value (Line (1 .. Last));
>I've seen C code use OS calls to open up a completely functional
> window and type "Hello World" on my Amiga in less lines of code than it would
> take to implement this heavyweight string parser.
No, you don't have to write a string parser. That has already been
done: the operation Get (From : in String; ...), and the attribute
T'Value.
> And when I think some source I copied out of an assembly book could
> reset my machine in 380 bytes of code once compiled I just want to
> cry! I think I'm beginning to hate this part of my uni course... :-/
It's not that bad; I may have confused you with my earlier post.
> Anyway, thanks for the advice. I think I'll keep in mind the vague operation
> of the wonderful get() in the future and compensate accordingly.
Remember, there are two Get operations.
1) One to fetch the data and convert it to a number:
Get (Item : out Num; ...)
2) Another to just convert a string to a number.
Get (From : in String; Item : out Num; ...);
I recommend that for processing text entered by a human user, you use
the second Get, and not the first.
> Its actually cheaper purely in terms of clock cycles just to insert a
> get_line() to compensate for get()'s inadequacies.
It's not an efficiency issue. You're doing the same work using either
techniques: first move data, then convert data. I'm arguing that you
keep the work as two explicit steps.
> Oh well. I'm sure there's something nice about Ada somewhere. Maybe
> she was a pretty girl or something ;)
There are many nice things about Ada. You just have to give the
language a chance to work for you.
next parent reply other threads:[~1999-03-30 0:00 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <yam7758.1500.1147822784@post.demon.co.uk>
1999-03-30 0:00 ` Matthew Heaney [this message]
1999-03-28 0:00 Weird get_line() W1bBle
1999-03-28 0:00 ` Matthew Heaney
1999-03-28 0:00 ` W1bBle
1999-03-29 0:00 ` Matthew Heaney
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox