comp.lang.ada
 help / color / mirror / Atom feed
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.














       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