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
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
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
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
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
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
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
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
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).
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
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
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!
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)
What about these syntaxes, should we keep them ? Number readFrom: '2r-11'. Number readFrom: '-2r-11'.
They are not in VW. Are they ANSI, ST-80 or whatever ? Is Squeak syntax officially defined anywhere (EBNF) ?
Nicolas
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.
I want to parse 1.23 and that is not a Smalltalk number, it is a number. If I read '' from a csv file, from a user input or a free-form text as what could or should be a number, the data point is undefined, and nil is expressing that literally.
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.
There is no problem or error unless you define that Number>>readFrom: has to be and can only be used when Squeak had written a "Smalltalk number" out and now has to get it back.
@Nicolas: I find your proposal of readFrom:ifFail: to be somewhat overkill. An exception/error seems simpler and more direct to me.
Prohibiting overkill solutions was the pragmatical point of my suggestion.
Regards, Martin
I want to parse 1.23 and that is not a Smalltalk number, it is a number. If I read '' from a csv file, from a user input or a free-form text as what could or should be a number, the data point is undefined, and nil is expressing that literally.
Hi Martin, I persist to think that getting a nil is rarely the aimed feature, and it will mostly be used as a C-style way to indicate a failure (exactly like fopen() returning NULL). As Andreas suggested, browse senders of readFrom: in a 3.9 image, and tell us where a nil answer would make sense.
Doing so, you will notice a single ifError: []. What we can conclude is that no-one is prepared for the possibility of failure... So, some code might have to be debugged anyway when we change the behavior and do not answer 0 anymore. (or maybe we will found so far hidden bugs).
If we adopt ^nil, methods will not fail while reading, they will fail latter when using the value, and that may be far latter, making the bug less explicit to track. This is true for future code also, we are all either lazy, or not prepared to write C-style-code, and a few will assert ifNil:.
If we adopt the exception, the method will fail, but with debugger opened exactly at the place where the origin of the problem is.
And if you really want the nil, no problem, you write value := [Number readFrom: stream] ifError: [nil]. With a resumable exception, you can easily catch that once for all [ MyCvsApp doSomething ] on: NumberParsingError do: [:exc | exc resume: nil].
One can also resume: 0, if one's app requires this as a feature...
Sorry that you have to write extra-code, but it seems that our laziness is superior to yours...
Nicolas
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
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
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 :)).
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" diegof79@gmail.com To: ncellier@ifrance.com; "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org 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 :)).
Francisco Garau wrote:
This would be both flexible and generic.
And complete and utter overkill in my understanding ;-) Yes, of course, you can do what you just described but by the end of the day, there are two prevalent use cases: 1) I want to read a "Squeak number", e.g., I want to read whatever is considered a valid numeric literal in Squeak. 2) I want to read "something else" and it doesn't matter whether that "something else" is a roman number, a scientific one, a .csv data record. What does matter is that Squeak cannot possibly provide parsers for all numeric formats ever in existence, and neither should it. What it should do is to read its own literals correctly and quickly.
Therefore (coming back to the starting point of this discussion) for Number/Integer/Float>>readFrom: (which by definition are within use case 1) we should not overly generalize reading numbers to the point where it's both slow and gets nothing quite right (since there are almost certainly ambiguous representations). What we should do is to fix what is broken and nothing more; namely that reading a number from an empty string answers zero.
And if you feel that you need more flexibility and format support than Squeak currently provides, feel free to set up a Numeric Parser project on SqueakSource and put that parser there fore anyone to use who needs it. This leaves plenty of room for experimentation (like substituting Number>>readFrom: in the way you are suggesting) and doesn't get into the way of fixing the bug that started the whole discussion.
Cheers, - Andreas
Francisco Garau wrote:
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" diegof79@gmail.com To: ncellier@ifrance.com; "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org 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 :)).
+ 1
Stef
On 28 avr. 06, at 01:45, Andreas Raab wrote:
Francisco Garau wrote:
This would be both flexible and generic.
And complete and utter overkill in my understanding ;-) Yes, of course, you can do what you just described but by the end of the day, there are two prevalent use cases: 1) I want to read a "Squeak number", e.g., I want to read whatever is considered a valid numeric literal in Squeak. 2) I want to read "something else" and it doesn't matter whether that "something else" is a roman number, a scientific one, a .csv data record. What does matter is that Squeak cannot possibly provide parsers for all numeric formats ever in existence, and neither should it. What it should do is to read its own literals correctly and quickly.
Therefore (coming back to the starting point of this discussion) for Number/Integer/Float>>readFrom: (which by definition are within use case 1) we should not overly generalize reading numbers to the point where it's both slow and gets nothing quite right (since there are almost certainly ambiguous representations). What we should do is to fix what is broken and nothing more; namely that reading a number from an empty string answers zero.
And if you feel that you need more flexibility and format support than Squeak currently provides, feel free to set up a Numeric Parser project on SqueakSource and put that parser there fore anyone to use who needs it. This leaves plenty of room for experimentation (like substituting Number>>readFrom: in the way you are suggesting) and doesn't get into the way of fixing the bug that started the whole discussion.
Cheers,
- Andreas
Francisco Garau wrote:
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" diegof79@gmail.com To: ncellier@ifrance.com; "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org 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 :)).
submit tests!
Stef
On 28 avr. 06, at 01:21, Francisco Garau wrote:
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" diegof79@gmail.com To: ncellier@ifrance.com; "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org 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 :)).
On 2006 April 26 17:34, 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.
Would it make sense to answer NaN?
Milan
(If "Number" was "float", is there a rule for such conversion in IEEE754?)
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
squeak-dev@lists.squeakfoundation.org