Fun with Number readFrom: What should we do ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
37 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
Hello all,

i noticed that Number readFrom: silently answers 0 when it does not encounter
some digits:

    Number readFrom: '' readStream.
    Number readFrom: 'foo-bar' readStream.
    Number readFrom: '.' readStream.

will all answer 0. Well, i believe there must have been discussions whether or
not raising an exception in this case, at least recently in vw list.
But let us say that answering 0 is a feature.


Then try:

    Number readFrom: 'rules are made for the others' readStream.

fail with an error: 'Invalid radix'.
Well, well, don't tell me it is a feature.


And just for fun, this one:

    Number readFrom: '.e' readStream.

ah, another feature UndefinedObject doesNotUnderstand: #digitValue.


Still want to play ? Try this one:

    Number readFrom: '--1' readStream.

Amazing what we can do with just one readFrom:...


Funny, it also accept some un-Smalltalk-ish syntax:

    Number readFrom: '.1e2'.
    Number readFrom: '1.e1'.

will answer a Float (10.0 like FORTRAN).
I suppose this one is intentionnaly a feature.


I will not analyze here the cases when the stream advance, and the cases when
it does not... That would be boring...


Now i am trying to implement Float readFrom without accumulating rounding
errors, and this can be the right time for deciding about these cases.

What do you vote for ? exception, answering 0, any other idea ?
What to do with the stream in case of error ? rewind, keep in place ?
I'am waiting for your comments.

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Andreas.Raab
Clearly, that's a bug not a feature. And it should raise an exception -
the empty string is *not* a valid zero value (but if anyone needs that
behavior they can handle the exception). About stream rewinding: Doesn't
matter - I don't think anyone should rely on stream positioning in the
case of an error.

Cheers,
   - Andreas

nicolas cellier wrote:

> Hello all,
>
> i noticed that Number readFrom: silently answers 0 when it does not encounter
> some digits:
>
>     Number readFrom: '' readStream.
>     Number readFrom: 'foo-bar' readStream.
>     Number readFrom: '.' readStream.
>
> will all answer 0. Well, i believe there must have been discussions whether or
> not raising an exception in this case, at least recently in vw list.
> But let us say that answering 0 is a feature.
>
>
> Then try:
>
>     Number readFrom: 'rules are made for the others' readStream.
>
> fail with an error: 'Invalid radix'.
> Well, well, don't tell me it is a feature.
>
>
> And just for fun, this one:
>
>     Number readFrom: '.e' readStream.
>
> ah, another feature UndefinedObject doesNotUnderstand: #digitValue.
>
>
> Still want to play ? Try this one:
>
>     Number readFrom: '--1' readStream.
>
> Amazing what we can do with just one readFrom:...
>
>
> Funny, it also accept some un-Smalltalk-ish syntax:
>
>     Number readFrom: '.1e2'.
>     Number readFrom: '1.e1'.
>
> will answer a Float (10.0 like FORTRAN).
> I suppose this one is intentionnaly a feature.
>
>
> I will not analyze here the cases when the stream advance, and the cases when
> it does not... That would be boring...
>
>
> Now i am trying to implement Float readFrom without accumulating rounding
> errors, and this can be the right time for deciding about these cases.
>
> What do you vote for ? exception, answering 0, any other idea ?
> What to do with the stream in case of error ? rewind, keep in place ?
> I'am waiting for your comments.
>
> Nicolas
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
I fully agree, but since it is a long living bug, present in other dialects,
maybe someone have used it as a feature, so it's better asking.

What about the FORTRANISH 1.e1 and .1e2 ? Anyone use it ?
I like it because i had apps reading this kind of format, but maybe my opinion
is biased... Another specific selector able to read +.1e+2 might be better...
One point of view is to enforce Smalltalk syntax only in readFrom:
On the other hand we have already the nan and infinity exceptions...

Nicolas

Le Mercredi 26 Avril 2006 23:45, Andreas Raab a écrit :
> Clearly, that's a bug not a feature. And it should raise an exception -
> the empty string is *not* a valid zero value (but if anyone needs that
> behavior they can handle the exception). About stream rewinding: Doesn't
> matter - I don't think anyone should rely on stream positioning in the
> case of an error.
>
> Cheers,
>    - Andreas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Andreas.Raab
nicolas cellier wrote:
> I fully agree, but since it is a long living bug, present in other dialects,
> maybe someone have used it as a feature, so it's better asking.

I agree it's good style to ask. Though, I was literally *gasp*ing when I
read your message (along the lines of "that can't *possibly* be; what a
mad bug...")

> What about the FORTRANISH 1.e1 and .1e2 ? Anyone use it ?
> I like it because i had apps reading this kind of format, but maybe my opinion
> is biased... Another specific selector able to read +.1e+2 might be better...
> One point of view is to enforce Smalltalk syntax only in readFrom:
> On the other hand we have already the nan and infinity exceptions...

I'm slightly against it, just on the grounds that less "special" forms
to support is better in general. However, I could be convinced otherwise.

Cheers,
   - Andreas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

stéphane ducasse-2
In reply to this post by Nicolas Cellier-3
Nicolas

I would:
        write some Unit tests that cover all the bugs you identified.
        propose a fix.
I agree with andreas and relying on '' as 0 is indeed a problem but  
we should improve stepwise.

Stef

On 27 avr. 06, at 00:18, nicolas cellier wrote:

> I fully agree, but since it is a long living bug, present in other  
> dialects,
> maybe someone have used it as a feature, so it's better asking.
>
> What about the FORTRANISH 1.e1 and .1e2 ? Anyone use it ?
> I like it because i had apps reading this kind of format, but maybe  
> my opinion
> is biased... Another specific selector able to read +.1e+2 might be  
> better...
> One point of view is to enforce Smalltalk syntax only in readFrom:
> On the other hand we have already the nan and infinity exceptions...
>
> Nicolas
>
> Le Mercredi 26 Avril 2006 23:45, Andreas Raab a écrit :
>> Clearly, that's a bug not a feature. And it should raise an  
>> exception -
>> the empty string is *not* a valid zero value (but if anyone needs  
>> that
>> behavior they can handle the exception). About stream rewinding:  
>> Doesn't
>> matter - I don't think anyone should rely on stream positioning in  
>> the
>> case of an error.
>>
>> Cheers,
>>    - Andreas
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Martin Wirblat
In reply to this post by Nicolas Cellier-3
nicolas cellier wrote:
...

>
> What do you vote for ? exception, answering 0, any other idea ?
> What to do with the stream in case of error ? rewind, keep in place ?
> I'am waiting for your comments.
>

Answering nil of course. To answer 0 is outright wrong and raising an
exception is at least to cumbersome. One could rate it being wrong too,
because unknown text that has to be converted is a valid input, and thus
finding no correct float is a valid result - nil.

Regards,
Martin

Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
Le Jeudi 27 Avril 2006 12:14, vous avez écrit :

> nicolas cellier wrote:
> ...
>
> > What do you vote for ? exception, answering 0, any other idea ?
> > What to do with the stream in case of error ? rewind, keep in place ?
> > I'am waiting for your comments.
>
> Answering nil of course. To answer 0 is outright wrong and raising an
> exception is at least to cumbersome. One could rate it being wrong too,
> because unknown text that has to be converted is a valid input, and thus
> finding no correct float is a valid result - nil.
>
> Regards,
> Martin

Hi Martin
Of course, answering nil is an obvious possibility better than answering 0.
I longly used this construction before i discovered exceptions, and i will try
to explain why i have switched to this second preferable style.

Answering nil is exactly the policy adopted in C programs.
It means that when you write a line of code, you will have 3 lines following
for handling problems.
If you omit this post-checking, your C programs can have weird behaviours like
dumping a core later when uninitialzed values will be used...

The FORTRAN way was better (i think of the READ() instruction):
- default was to abort the program with an error message (brutal but clean)
- it was possible to pass a label to branch on in case of error (an early
exception handling mechanism).

In Smalltalk, we have those nice soft aborption with debugger, better than a
core dumped, but that does not solve everything, and in fact we face the same
choice that C-FORTRAN explained above:

Suppose we adopt the nil answer.
We will have to check for nil after each readFrom: instruction.
If we lazily omit those nil-checking lines, the problem can appear well later
in the code when we will try and use the value, and the debugger will not be
of much use, because it won't point directly at the place where the problem
come from (the C core dumped case)...

If i have a method with 10 readFrom: , i will have 10 ifNil: blocks for
handling the exception.
Maybe the handling can consist simply in answering nil in our turn and reject
the problem to the sender method, wich will have to check ifNil: in its turn
und so weiter...
What i dislike in this C-style is that it makes code less readable because
main algorithm is scattered among exception handling code.

Suppose now we adopt an exception mechanism.
I am lazy and do not put an exception handling block (working on a prototype).
Then the debugger will open exactly where the problem occured.
I am smarter with the users of my programs and provide an exception handling
block: then i can factor several exceptions in a single block (the case when
i do 10 readFrom:), and i can handle the problem several senders above
without adding noisy ifNil: at each level.

The problem with exception is that if i trap Error, i will trap too many
errors, not only the readFrom: error. This is not selective enough. This has
already been discussed on the list, when to create a new exception class ?
but i do not have the feeling we got a clear answer...
Untill we address this problem, your ^nil proposition is a candidate though
not my favourite style. Maybe readFrom: can also call readFrom:ifFail: the
way Dictionary at: call at:ifAbsent:.

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
In reply to this post by Martin Wirblat
Le Jeudi 27 Avril 2006 12:14, vous avez écrit :

> nicolas cellier wrote:
> ...
>
> > What do you vote for ? exception, answering 0, any other idea ?
> > What to do with the stream in case of error ? rewind, keep in place ?
> > I'am waiting for your comments.
>
> Answering nil of course. To answer 0 is outright wrong and raising an
> exception is at least to cumbersome. One could rate it being wrong too,
> because unknown text that has to be converted is a valid input, and thus
> finding no correct float is a valid result - nil.
>
> Regards,
> Martin

I will formulate my first answer in good Smalltalk, this will be more
expressive than my bad english:

My proposition is:

Number>>readFrom: aStringOrStream
    ^self readFrom: aStringOrStream ifFail: [^self error: 'cannot read a
number']

If nil is what you want, you will have to write:
    value := Number readFrom: aStream ifFail: [nil].
A little longer than your proposition:
    value := Number readfrom: aStream.

But in the case you really want an exception (i guess this is most wanted
behavior), mine is better:
    value := Number readfrom: aStream.
Yours would be:
    (value := Number readFrom: aStream) ifNil: [self error: 'etc...'].

And if you have a local exception handling:
    value := Number readFrom: aStream ifFail: [local handler block]
not much different from what would be implied by your proposition:
    (value := Number readFrom: aStream) ifNil: [local handler block]

But with mine, you can also have a global exception handling:
  [value1 := Number readfrom: aStream.
    value2 := Number readFrom: aStream]
      ifError: [global handler block]

Maybe a new exception class is better than Error, but i do not take this
responsability alone.
  [value1 := Number readfrom: aStream.
    value2 := Number readFrom: aStream]
      on: NumberReadError do: [:exc | global handler block]

Hope i convinced someone.

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3

> But with mine, you can also have a global exception handling:
>   [value1 := Number readfrom: aStream.
>     value2 := Number readFrom: aStream]
>       ifError: [global handler block]
>
> Maybe a new exception class is better than Error, but i do not take this
> responsability alone.
>   [value1 := Number readfrom: aStream.
>     value2 := Number readFrom: aStream]
>       on: NumberReadError do: [:exc | global handler block]
>
> Hope i convinced someone.
>
> Nicolas

i hadn't noticed the typo (lowercase f instead of F in readFrom:) in my
example, but this is an excellent explanation why a specific error is better.

The first block will catch the Number class doesNotUnderstand: #readfrom: ,
That is it will catch my programming error...
That is we always get the exception handling block even with a good stream...

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Martin Wirblat
In reply to this post by Nicolas Cellier-3
Nicolas,

you are arguing form the premise that some string that is not
convertible to a float is a problem, an error or an exception. Consider
a csv file. You would read it with upTo: $;. If you get an empty string
it does not mean that an error occurred, it means that a piece of
information is not applicable or available. That is valid information
and not an error! There are csv files with more than 99% of such empty
fields.

The same holds true for an unformatted text from which information has
to be extracted. It is expected that at many places a piece of
information may or may not appear. And because it is expected it can't
be an exception ;)

I think if a string can't be converted to a float almost never an error
should be raised. And if so, some very specific reason has to exist,
some reason that makes this scenario a real - unforeseeable - error.

For me the bottom line of the 'exception thread' was exactly this: an
error or an exception is something which is unforeseeable. If you can
predict that it may happen or if it regularly happens it should get
handled directly.

Perhaps even more straight: If *possible* it should be handled directly.
Error handlers are reserved for cases where you don't know when or where
exactly what may go wrong.

Regards,
Martin


nicolas cellier wrote:

> Le Jeudi 27 Avril 2006 12:14, vous avez écrit :
>
>>nicolas cellier wrote:
>>...
>>
>>
>>>What do you vote for ? exception, answering 0, any other idea ?
>>>What to do with the stream in case of error ? rewind, keep in place ?
>>>I'am waiting for your comments.
>>
>>Answering nil of course. To answer 0 is outright wrong and raising an
>>exception is at least to cumbersome. One could rate it being wrong too,
>>because unknown text that has to be converted is a valid input, and thus
>>finding no correct float is a valid result - nil.
>>
>>Regards,
>>Martin
>
>
> Hi Martin
> Of course, answering nil is an obvious possibility better than answering 0.
> I longly used this construction before i discovered exceptions, and i will try
> to explain why i have switched to this second preferable style.
>
> Answering nil is exactly the policy adopted in C programs.
> It means that when you write a line of code, you will have 3 lines following
> for handling problems.
> If you omit this post-checking, your C programs can have weird behaviours like
> dumping a core later when uninitialzed values will be used...
>
> The FORTRAN way was better (i think of the READ() instruction):
> - default was to abort the program with an error message (brutal but clean)
> - it was possible to pass a label to branch on in case of error (an early
> exception handling mechanism).
>
> In Smalltalk, we have those nice soft aborption with debugger, better than a
> core dumped, but that does not solve everything, and in fact we face the same
> choice that C-FORTRAN explained above:
>
> Suppose we adopt the nil answer.
> We will have to check for nil after each readFrom: instruction.
> If we lazily omit those nil-checking lines, the problem can appear well later
> in the code when we will try and use the value, and the debugger will not be
> of much use, because it won't point directly at the place where the problem
> come from (the C core dumped case)...
>
> If i have a method with 10 readFrom: , i will have 10 ifNil: blocks for
> handling the exception.
> Maybe the handling can consist simply in answering nil in our turn and reject
> the problem to the sender method, wich will have to check ifNil: in its turn
> und so weiter...
> What i dislike in this C-style is that it makes code less readable because
> main algorithm is scattered among exception handling code.
>
> Suppose now we adopt an exception mechanism.
> I am lazy and do not put an exception handling block (working on a prototype).
> Then the debugger will open exactly where the problem occured.
> I am smarter with the users of my programs and provide an exception handling
> block: then i can factor several exceptions in a single block (the case when
> i do 10 readFrom:), and i can handle the problem several senders above
> without adding noisy ifNil: at each level.
>
> The problem with exception is that if i trap Error, i will trap too many
> errors, not only the readFrom: error. This is not selective enough. This has
> already been discussed on the list, when to create a new exception class ?
> but i do not have the feeling we got a clear answer...
> Untill we address this problem, your ^nil proposition is a candidate though
> not my favourite style. Maybe readFrom: can also call readFrom:ifFail: the
> way Dictionary at: call at:ifAbsent:.
>
> Nicolas
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Diego Fernández
In reply to this post by Nicolas Cellier-3
> My proposition is:
>
> Number>>readFrom: aStringOrStream
>     ^self readFrom: aStringOrStream ifFail: [^self error: 'cannot read a
> number']
>
> If nil is what you want, you will have to write:
>     value := Number readFrom: aStream ifFail: [nil].
> A little longer than your proposition:
>     value := Number readfrom: aStream.

The mine is:
Number>>readFrom: aStringOrStream
      ^NumberParser new parse: aStringOrStream

NumberParser>>parse: aStringOrStream
       "on failure"
        NumberParsingException signal
        "or just ParseException"

I think that #readFrom: must be an extension of Number.
So if you want more control of the parsing you can configure an
instance of NumberParser.
(may be you can have a FortranNumberParser :)).

Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
In reply to this post by Nicolas Cellier-3
I agree, my prop was low level, yours is higher level (extensible)

Nicolas

Diego Fernandez:
> My proposition is:
>
> Number>>readFrom: aStringOrStream
> ^self readFrom: aStringOrStream ifFail: [^self error: 'cannot read a
> number']
>
> If nil is what you want, you will have to write:
> value := Number readFrom: aStream ifFail: [nil].
> A little longer than your proposition:
> value := Number readfrom: aStream.

The mine is:
Number>>readFrom: aStringOrStream
^NumberParser new parse: aStringOrStream

NumberParser>>parse: aStringOrStream
"on failure"
NumberParsingException signal
"or just ParseException"

I think that #readFr om: must be an extension of Number.
So if you want more control of the parsing you can configure an
instance of NumberParser.
(may be you can have a FortranNumberParser :)).



iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
In reply to this post by Nicolas Cellier-3
I agree with your example, but not with your words.

You don't know whether you can read a double or not in advance.
So what you do ?
You don't test if you can read a number as a precondition, because that would be the same as duplicating a large part of Number readFrom: code.
What you do instead is trial and error. You're trying to read a Number, if it fails you do another thing.
Exception are well fitted for that case.

What i proposed readFrom:ifFail: is exactly corresponding to trial and error approach

Nicolas


Martin Wirblat:
Nicolas,

you are arguing form the premise that some string that is not
convertible to a float is a problem, an error or an exception. Consider
a csv file. You would read it with upTo: $;. If you get an empty string
it does not mean that an error occurred, it means that a piece of
information is not applicable or available. That is valid information
and not an error! There are csv files with more than 99% of such empty
fields.

The same holds true for an unformatted text from which information has
to be extracted. It is expected that at many places a piece of
information may or may not appear. And because it is expected it can't
be an exception ;)

I think if a string can't be converted to a float almost never an error
should be raised. And if so, some very specific reason has to exist,
some reason that makes this scenario a real - unforeseeable - error.

For me the bottom line of the 'exception thread' was exactly this: an
error or an exception is something which is unforeseeable. If you can
predict that it may happen or if it regularly happens it should get
handled directly.
< br /> Perhaps even more straight: If *possible* it should be handled directly.
Error handlers are reserved for cases where you don't know when or where
exactly what may go wrong.

Regards,
Martin


nicolas cellier wrote:
> Le Jeudi 27 Avril 2006 12:14, vous avez écrit :
>
>>nicolas cellier wrote:
>>...
>>
>>
>>>What do you vote for ? exception, answering 0, any other idea ?
>>>What to do with the stream in case of error ? rewind, keep in place ?
>>>I'am waiting for your comments.
>>
>>Answering nil of course. To answer 0 is outright wrong and raising an
>>exception is at least to cumbersome. One could rate it being wrong too,
>>because unknown text that has to be converted is a valid input, and thus
>>finding no correct float is a valid resul t - nil.
>>
>>Regards,
>>Martin
>
>
> Hi Martin
> Of course, answering nil is an obvious possibility better than answering 0.
> I longly used this construction before i discovered exceptions, and i will try
> to explain why i have switched to this second preferable style.
>
> Answering nil is exactly the policy adopted in C programs.
> It means that when you write a line of code, you will have 3 lines following
> for handling problems.
> If you omit this post-checking, your C programs can have weird behaviours like
> dumping a core later when uninitialzed values will be used...
>
> The FORTRAN way was better (i think of the READ() instruction):
> - default was to abort the program with an error message (brutal but clean)
> - it was possible to pass a label to branch on in case of error (an e arly
> exception handling mechanism).
>
> In Smalltalk, we have those nice soft aborption with debugger, better than a
> core dumped, but that does not solve everything, and in fact we face the same
> choice that C-FORTRAN explained above:
>
> Suppose we adopt the nil answer.
> We will have to check for nil after each readFrom: instruction.
> If we lazily omit those nil-checking lines, the problem can appear well later
> in the code when we will try and use the value, and the debugger will not be
> of much use, because it won't point directly at the place where the problem
> come from (the C core dumped case)...
>
> If i have a method with 10 readFrom: , i will have 10 ifNil: blocks for
> handling the exception.
> Maybe the handling can consist simply in answering nil in our turn and reject
> the problem to th e sender method, wich will have to check ifNil: in its turn
> und so weiter...
> What i dislike in this C-style is that it makes code less readable because
> main algorithm is scattered among exception handling code.
>
> Suppose now we adopt an exception mechanism.
> I am lazy and do not put an exception handling block (working on a prototype).
> Then the debugger will open exactly where the problem occured.
> I am smarter with the users of my programs and provide an exception handling
> block: then i can factor several exceptions in a single block (the case when
> i do 10 readFrom:), and i can handle the problem several senders above
> without adding noisy ifNil: at each level.
>
> The problem with exception is that if i trap Error, i will trap too many
> errors, not only the readFrom: error. This is not selective enough. This has
> ; already been discussed on the list, when to create a new exception class ?
> but i do not have the feeling we got a clear answer...
> Untill we address this problem, your ^nil proposition is a candidate though
> not my favourite style. Maybe readFrom: can also call readFrom:ifFail: the
> way Dictionary at: call at:ifAbsent:.
>
> Nicolas
>
>
>




iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Chris Muller-2
In reply to this post by Martin Wirblat
> For me the bottom line of the 'exception thread' was exactly this: an
> error or an exception is something which is unforeseeable. If you can
> predict that it may happen or if it regularly happens it should get
> handled directly.

 Not sure I'm reading you right but exception handling of foreseeable exceptions provides powerful stack-unwinding capabilities and generic handling that is extremely useful.  Under your argument you'd have to have checks at every level in your code, yuck.
 
 I think the Java camp agrees, they have partitioned their exceptions into "Runtime" (unforeseeable) and "Checked" (foreseeable).




Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Andreas.Raab
In reply to this post by Martin Wirblat
The example of the csv file is very badly chosen IMO. CSV files contain
many different things and applying the same logic you are using for
numbers here would dictate that String>>readFrom: also answer nil when
trying to read from an empty string. Moreover, it would dictate that
Strings use double quotes (if I remember my .csv corretly). This has
nothing to do with the discussion here - .csv files do NOT contain
"Smalltalk numbers" so to speak, therefore they need to be separately
parsed and analyzed and arguing that an empty string should parse as nil
because .csv files have empty fields is really besides the point of this
discussion.

Number>>readFrom: has the specific intent to read a literal number from
a stream. I have yet to find a caller that could even deal with the fact
that this method may answer nil. This goes mostly to show at what a low
level number parsing is typically used (e.g., all the error checking
happens mostly at a higher level) which speaks very clearly for having
an exception raised to signal the problem.

@Nicolas: I find your proposal of readFrom:ifFail: to be somewhat
overkill. An exception/error seems simpler and more direct to me.

Cheers,
   - Andreas


Martin Wirblat wrote:

> Nicolas,
>
> you are arguing form the premise that some string that is not
> convertible to a float is a problem, an error or an exception. Consider
> a csv file. You would read it with upTo: $;. If you get an empty string
> it does not mean that an error occurred, it means that a piece of
> information is not applicable or available. That is valid information
> and not an error! There are csv files with more than 99% of such empty
> fields.
>
> The same holds true for an unformatted text from which information has
> to be extracted. It is expected that at many places a piece of
> information may or may not appear. And because it is expected it can't
> be an exception ;)
>
> I think if a string can't be converted to a float almost never an error
> should be raised. And if so, some very specific reason has to exist,
> some reason that makes this scenario a real - unforeseeable - error.
>
> For me the bottom line of the 'exception thread' was exactly this: an
> error or an exception is something which is unforeseeable. If you can
> predict that it may happen or if it regularly happens it should get
> handled directly.
>
> Perhaps even more straight: If *possible* it should be handled directly.
> Error handlers are reserved for cases where you don't know when or where
> exactly what may go wrong.
>
> Regards,
> Martin
>
>
> nicolas cellier wrote:
>> Le Jeudi 27 Avril 2006 12:14, vous avez écrit :
>>
>>> nicolas cellier wrote:
>>> ...
>>>
>>>
>>>> What do you vote for ? exception, answering 0, any other idea ?
>>>> What to do with the stream in case of error ? rewind, keep in place ?
>>>> I'am waiting for your comments.
>>>
>>> Answering nil of course. To answer 0 is outright wrong and raising an
>>> exception is at least to cumbersome. One could rate it being wrong too,
>>> because unknown text that has to be converted is a valid input, and thus
>>> finding no correct float is a valid result - nil.
>>>
>>> Regards,
>>> Martin
>>
>>
>> Hi Martin
>> Of course, answering nil is an obvious possibility better than
>> answering 0.
>> I longly used this construction before i discovered exceptions, and i
>> will try to explain why i have switched to this second preferable style.
>>
>> Answering nil is exactly the policy adopted in C programs.
>> It means that when you write a line of code, you will have 3 lines
>> following for handling problems.
>> If you omit this post-checking, your C programs can have weird
>> behaviours like dumping a core later when uninitialzed values will be
>> used...
>>
>> The FORTRAN way was better (i think of the READ() instruction):
>> - default was to abort the program with an error message (brutal but
>> clean)
>> - it was possible to pass a label to branch on in case of error (an
>> early exception handling mechanism).
>>
>> In Smalltalk, we have those nice soft aborption with debugger, better
>> than a core dumped, but that does not solve everything, and in fact we
>> face the same choice that C-FORTRAN explained above:
>>
>> Suppose we adopt the nil answer.
>> We will have to check for nil after each readFrom: instruction.
>> If we lazily omit those nil-checking lines, the problem can appear
>> well later in the code when we will try and use the value, and the
>> debugger will not be of much use, because it won't point directly at
>> the place where the problem come from (the C core dumped case)...
>>
>> If i have a method with 10 readFrom: , i will have 10 ifNil: blocks
>> for handling the exception.
>> Maybe the handling can consist simply in answering nil in our turn and
>> reject the problem to the sender method, wich will have to check
>> ifNil: in its turn und so weiter...
>> What i dislike in this C-style is that it makes code less readable
>> because main algorithm is scattered among exception handling code.
>>
>> Suppose now we adopt an exception mechanism.
>> I am lazy and do not put an exception handling block (working on a
>> prototype). Then the debugger will open exactly where the problem
>> occured.
>> I am smarter with the users of my programs and provide an exception
>> handling block: then i can factor several exceptions in a single block
>> (the case when i do 10 readFrom:), and i can handle the problem
>> several senders above without adding noisy ifNil: at each level.
>>
>> The problem with exception is that if i trap Error, i will trap too
>> many errors, not only the readFrom: error. This is not selective
>> enough. This has already been discussed on the list, when to create a
>> new exception class ? but i do not have the feeling we got a clear
>> answer...
>> Untill we address this problem, your ^nil proposition is a candidate
>> though not my favourite style. Maybe readFrom: can also call
>> readFrom:ifFail: the way Dictionary at: call at:ifAbsent:.
>>
>> Nicolas
>>
>>
>>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

stéphane ducasse-2
Just to say that I really enjoy reading this discussion.
Please continue and conclude with some enh, fix and tests. Excellent!

On 27 avr. 06, at 20:34, Andreas Raab wrote:

> The example of the csv file is very badly chosen IMO. CSV files  
> contain many different things and applying the same logic you are  
> using for numbers here would dictate that String>>readFrom: also  
> answer nil when trying to read from an empty string. Moreover, it  
> would dictate that Strings use double quotes (if I remember my .csv  
> corretly). This has nothing to do with the discussion here - .csv  
> files do NOT contain "Smalltalk numbers" so to speak, therefore  
> they need to be separately parsed and analyzed and arguing that an  
> empty string should parse as nil because .csv files have empty  
> fields is really besides the point of this discussion.
>
> Number>>readFrom: has the specific intent to read a literal number  
> from a stream. I have yet to find a caller that could even deal  
> with the fact that this method may answer nil. This goes mostly to  
> show at what a low level number parsing is typically used (e.g.,  
> all the error checking happens mostly at a higher level) which  
> speaks very clearly for having an exception raised to signal the  
> problem.
>
> @Nicolas: I find your proposal of readFrom:ifFail: to be somewhat  
> overkill. An exception/error seems simpler and more direct to me.
>
> Cheers,
>   - Andreas
>
>
> Martin Wirblat wrote:
>> Nicolas,
>> you are arguing form the premise that some string that is not  
>> convertible to a float is a problem, an error or an exception.  
>> Consider a csv file. You would read it with upTo: $;. If you get  
>> an empty string it does not mean that an error occurred, it means  
>> that a piece of information is not applicable or available. That  
>> is valid information and not an error! There are csv files with  
>> more than 99% of such empty fields.
>> The same holds true for an unformatted text from which information  
>> has to be extracted. It is expected that at many places a piece of  
>> information may or may not appear. And because it is expected it  
>> can't be an exception ;)
>> I think if a string can't be converted to a float almost never an  
>> error should be raised. And if so, some very specific reason has  
>> to exist, some reason that makes this scenario a real -  
>> unforeseeable - error.
>> For me the bottom line of the 'exception thread' was exactly this:  
>> an error or an exception is something which is unforeseeable. If  
>> you can predict that it may happen or if it regularly happens it  
>> should get handled directly.
>> Perhaps even more straight: If *possible* it should be handled  
>> directly. Error handlers are reserved for cases where you don't  
>> know when or where exactly what may go wrong.
>> Regards,
>> Martin
>> nicolas cellier wrote:
>>> Le Jeudi 27 Avril 2006 12:14, vous avez écrit :
>>>
>>>> nicolas cellier wrote:
>>>> ...
>>>>
>>>>
>>>>> What do you vote for ? exception, answering 0, any other idea ?
>>>>> What to do with the stream in case of error ? rewind, keep in  
>>>>> place ?
>>>>> I'am waiting for your comments.
>>>>
>>>> Answering nil of course. To answer 0 is outright wrong and  
>>>> raising an
>>>> exception is at least to cumbersome. One could rate it being  
>>>> wrong too,
>>>> because unknown text that has to be converted is a valid input,  
>>>> and thus
>>>> finding no correct float is a valid result - nil.
>>>>
>>>> Regards,
>>>> Martin
>>>
>>>
>>> Hi Martin
>>> Of course, answering nil is an obvious possibility better than  
>>> answering 0.
>>> I longly used this construction before i discovered exceptions,  
>>> and i will try to explain why i have switched to this second  
>>> preferable style.
>>>
>>> Answering nil is exactly the policy adopted in C programs.
>>> It means that when you write a line of code, you will have 3  
>>> lines following for handling problems.
>>> If you omit this post-checking, your C programs can have weird  
>>> behaviours like dumping a core later when uninitialzed values  
>>> will be used...
>>>
>>> The FORTRAN way was better (i think of the READ() instruction):
>>> - default was to abort the program with an error message (brutal  
>>> but clean)
>>> - it was possible to pass a label to branch on in case of error  
>>> (an early exception handling mechanism).
>>>
>>> In Smalltalk, we have those nice soft aborption with debugger,  
>>> better than a core dumped, but that does not solve everything,  
>>> and in fact we face the same choice that C-FORTRAN explained above:
>>>
>>> Suppose we adopt the nil answer.
>>> We will have to check for nil after each readFrom: instruction.
>>> If we lazily omit those nil-checking lines, the problem can  
>>> appear well later in the code when we will try and use the value,  
>>> and the debugger will not be of much use, because it won't point  
>>> directly at the place where the problem come from (the C core  
>>> dumped case)...
>>>
>>> If i have a method with 10 readFrom: , i will have 10 ifNil:  
>>> blocks for handling the exception.
>>> Maybe the handling can consist simply in answering nil in our  
>>> turn and reject the problem to the sender method, wich will have  
>>> to check ifNil: in its turn und so weiter...
>>> What i dislike in this C-style is that it makes code less  
>>> readable because main algorithm is scattered among exception  
>>> handling code.
>>>
>>> Suppose now we adopt an exception mechanism.
>>> I am lazy and do not put an exception handling block (working on  
>>> a prototype). Then the debugger will open exactly where the  
>>> problem occured.
>>> I am smarter with the users of my programs and provide an  
>>> exception handling block: then i can factor several exceptions in  
>>> a single block (the case when i do 10 readFrom:), and i can  
>>> handle the problem several senders above without adding noisy  
>>> ifNil: at each level.
>>>
>>> The problem with exception is that if i trap Error, i will trap  
>>> too many errors, not only the readFrom: error. This is not  
>>> selective enough. This has already been discussed on the list,  
>>> when to create a new exception class ? but i do not have the  
>>> feeling we got a clear answer...
>>> Untill we address this problem, your ^nil proposition is a  
>>> candidate though not my favourite style. Maybe readFrom: can also  
>>> call readFrom:ifFail: the way Dictionary at: call at:ifAbsent:.
>>>
>>> Nicolas
>>>
>>>
>>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
Just to say that squeak learners (we all, and that includes newbies) can learn
a lot from this kind of discussions.

Nicolas

Le Jeudi 27 Avril 2006 21:41, stéphane ducasse a écrit :
> Just to say that I really enjoy reading this discussion.
> Please continue and conclude with some enh, fix and tests. Excellent!
>


Reply | Threaded
Open this post in threaded view
|

RE: Fun with Number readFrom: What should we do ?

Ramon Leon
In reply to this post by Nicolas Cellier-3
>
> Just to say that squeak learners (we all, and that includes
> newbies) can learn a lot from this kind of discussions.
>
> Nicolas
>
> Le Jeudi 27 Avril 2006 21:41, stéphane ducasse a écrit :
> > Just to say that I really enjoy reading this discussion.
> > Please continue and conclude with some enh, fix and tests.
> Excellent!
> >

Yes, everyone can learn a lot, I like seeing these things hashed out publicly as well because you get a peek at the thought processes of various people and can learn quite a bit about style from such interchanges.  -- Ramon Leon

Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Francisco Garau-2
In reply to this post by Diego Fernández
I totally agree with Diego.

Moreover, I think that each message should do the parsing on exactly one
format. Something like this:

    (SqNumberParser on: '1.23') number
    (SqNumberParser on: '1.23e4) scientificNotation; number
    (SqNumberParser on: '2r1111') base2Notation; number
    (SqNumberParser on: '') cvsNotation; number "would answer 0"

And then we can add a top level method to try several alternatives (in a
specific order)

    SqNumberParser>>parse
        try scientificNotation ifTrue: [^got it]
        try xxxNotation ifTrue: [^got it]
        try base2Notation ifTrue: [^got it]
        try base16Notation ifTrue: [^got it]
        else ParseException signal

This would be both flexible and generic. Those who know precisely the string
format of an expected number, can use the specific parse message. And if you
don't know the string format, just use the generic parse message.

String>>sqNumber
    ^(SqNumberParser on: self) parse; number

By using the Sq prefix, we would avoid clashing with existing methods. The
code that is relying on the current funny behaviour would remain unaffected.

Cheers,
Francisco


----- Original Message -----
From: "Diego Fernandez" <[hidden email]>
To: <[hidden email]>; "The general-purpose Squeak developers list"
<[hidden email]>
Sent: Thursday, April 27, 2006 2:59 PM
Subject: Re: Fun with Number readFrom: What should we do ?


> My proposition is:
>
> Number>>readFrom: aStringOrStream
>     ^self readFrom: aStringOrStream ifFail: [^self error: 'cannot read a
> number']
>
> If nil is what you want, you will have to write:
>     value := Number readFrom: aStream ifFail: [nil].
> A little longer than your proposition:
>     value := Number readfrom: aStream.

The mine is:
Number>>readFrom: aStringOrStream
      ^NumberParser new parse: aStringOrStream

NumberParser>>parse: aStringOrStream
       "on failure"
        NumberParsingException signal
        "or just ParseException"

I think that #readFrom: must be an extension of Number.
So if you want more control of the parsing you can configure an
instance of NumberParser.
(may be you can have a FortranNumberParser :)).


Reply | Threaded
Open this post in threaded view
|

Re: Fun with Number readFrom: What should we do ?

Nicolas Cellier-3
In reply to this post by stéphane ducasse-2

Just another question about scaled decimals:

This one truncate
     Number readFrom: '3.128s-2'
Should it round ?
Should it raise an error ? (VW do that)


12