(Integer readFrom: 'abc' readStream) = 0

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

(Integer readFrom: 'abc' readStream) = 0

Zulq Alam-2
I was surprised to find that Integer class>>#readFrom: returns 0 when it
doesn't find an integer. So, (Integer readFrom: 'abc' readStream) = 0 is
true. This seems wrong to me although it's consistent with the method
comment and VisualWorks. I was expecting an error. What's the reasoning
behind this?

I'm looking for the Smalltalk equivalent of:

try {
   Integer.parseInt("abc");
}
catch (NumberFormatException e) {
   // do something
}

I found SqNumberParser which appears to be what I want:

(SqNumberParser on: 'abc')
        nextIntegerBase: 10
        ifFail: [self doSomething]

This works but, is it the right / good way?

Does the Sq prefix mean this parser is expecting Squeak format numbers?
If so, what is this format?

Also, how is this done in other smalltalks?

Thanks,
Zulq.


Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Damien Cassou-3
On Jan 8, 2008 3:57 PM, Zulq Alam <[hidden email]> wrote:
> I was surprised to find that Integer class>>#readFrom: returns 0 when it
> doesn't find an integer. So, (Integer readFrom: 'abc' readStream) = 0 is


You should use #readExactlyFrom:


> true. This seems wrong to me although it's consistent with the method
> comment and VisualWorks. I was expecting an error. What's the reasoning
> behind this?
>
> I'm looking for the Smalltalk equivalent of:
>
> try {
>    Integer.parseInt("abc");
> }
> catch (NumberFormatException e) {
>    // do something
> }
>
> I found SqNumberParser which appears to be what I want:
>
> (SqNumberParser on: 'abc')
>         nextIntegerBase: 10
>         ifFail: [self doSomething]
>
> This works but, is it the right / good way?


Yes. SqNumberParser has been added in Squeak 3.9 and is the way to do
new number parsing.




--
Damien Cassou

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Nicolas Cellier-3
In reply to this post by Zulq Alam-2
Zulq Alam a écrit :
> What's the reasoning behind this?
>
None.

Historically, readFrom: was mainly used from Parser (or Scanner) to read
literal Number and only triggered by the presence of a digit character,
  in this context, reading from 'abc' would never have happened.

Syntax error would have been handled by Smalltalk Compiler too (Parser),
so no care was ever taken at readFrom: level.


That's all what is behind.
Our expectations and usage of readFrom: has evolved.

However, I always preferred the power of Compiler evaluate: to its very
restricted avatar Number readFrom:

example of non smart readFrom:
        Number readFrom: '1+1'.
        Number readFrom: 'Float pi / 5 sin * 30'.

Of course, you gotta trust your users then, not very secure...

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Zulq Alam-2
In reply to this post by Damien Cassou-3
Thanks Damien.

That's almost what I need, except '123abc' = 123 and '1.1' = 1, etc. I
think I want something more like this:

parseString: aString base: aBase ifFail: failBlock
        " Answer a new integer described by the whole string aString in
        base aBase. If the parse fails, return the value of the block
        failBlock."
       
        | stream integer |
        stream := aString readStream.
        integer := (SqNumberParser on: stream)
                nextIntegerBase: aBase
                ifFail: [^ failBlock value].
        stream atEnd ifFalse: [^ failBlock value].
        ^ integer

parseString: aString ifFail: failBlock
        " Answer a new integer described by the whole string aString in
        base 10. If the parse fails, return the value of the block
        failBlock."
       
        ^ self parseString: aString base: 10 ifFail: failBlock

Integer parseString: 'abc' ifFail: [#error] "#error"
Integer parseString: '123' ifFail: [#error] "123"
Integer parseString: '123abc' ifFail: [#error]. "#error"
Integer parseString: '1.1' ifFail: [#error]. "#error"
Integer parseString: '' ifFail: [#error] "#error"

Others might find this useful. Especially those looking for the
equivalent to Integer.parseInt in Java. What would be a good way for
making these types of changes available?

Thanks,
Zulq.

Damien Cassou wrote:
>
> You should use #readExactlyFrom:
>


Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Zulq Alam-2
In reply to this post by Nicolas Cellier-3
Thanks Nicolas.

I hate to think how many times I've used #readFrom: without knowing this!

nicolas cellier wrote:

> Zulq Alam a écrit :
>> What's the reasoning behind this?
>>
> None.
>
> Historically, readFrom: was mainly used from Parser (or Scanner) to read
> literal Number and only triggered by the presence of a digit character,
>  in this context, reading from 'abc' would never have happened.
>
> Syntax error would have been handled by Smalltalk Compiler too (Parser),
> so no care was ever taken at readFrom: level.
>
>
> That's all what is behind.
> Our expectations and usage of readFrom: has evolved.
>
> However, I always preferred the power of Compiler evaluate: to its very
> restricted avatar Number readFrom:
>
> example of non smart readFrom:
>     Number readFrom: '1+1'.
>     Number readFrom: 'Float pi / 5 sin * 30'.
>
> Of course, you gotta trust your users then, not very secure...
>
> Nicolas
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Damien Cassou-3
In reply to this post by Zulq Alam-2
On Jan 9, 2008 12:24 PM, Zulq Alam <[hidden email]> wrote:
> Others might find this useful. Especially those looking for the
> equivalent to Integer.parseInt in Java. What would be a good way for
> making these types of changes available?

Submit a bug report on mantis.

--
Damien Cassou

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Paolo Bonzini-2
In reply to this post by Zulq Alam-2
Zulq Alam wrote:

> Thanks Damien.
>
> That's almost what I need, except '123abc' = 123 and '1.1' = 1, etc. I
> think I want something more like this:
>
> parseString: aString base: aBase ifFail: failBlock
>     " Answer a new integer described by the whole string aString in
>     base aBase. If the parse fails, return the value of the block
>     failBlock."
>    
>     | stream integer |
>     stream := aString readStream.
>     integer := (SqNumberParser on: stream)
>         nextIntegerBase: aBase
>         ifFail: [^ failBlock value].
>     stream atEnd ifFalse: [^ failBlock value].
>     ^ integer
>
> parseString: aString ifFail: failBlock
>     " Answer a new integer described by the whole string aString in
>     base 10. If the parse fails, return the value of the block
>     failBlock."
>    
>     ^ self parseString: aString base: 10 ifFail: failBlock
>
> Integer parseString: 'abc' ifFail: [#error]     "#error"
> Integer parseString: '123' ifFail: [#error]     "123"
> Integer parseString: '123abc' ifFail: [#error]. "#error"
> Integer parseString: '1.1' ifFail: [#error].    "#error"
> Integer parseString: '' ifFail: [#error]     "#error"

Or:

parseString: aString base: aBase ifFail: failBlock
     " Answer a new integer described by the whole string aString in
     base aBase. If the parse fails, return the value of the block
     failBlock."

     | stream integer |
     stream := aString readStream.
     integer := (SqNumberParser on: stream)
         nextIntegerBase: aBase
         ifFail: [ failBlock value: nil].

     "Pass partial value to failBlock"
     stream atEnd ifFalse: [failBlock value: integer].
     ^ integer

Paolo

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Jason Johnson-5
In reply to this post by Nicolas Cellier-3
On Jan 8, 2008 9:43 PM, nicolas cellier <[hidden email]> wrote:

>
> However, I always preferred the power of Compiler evaluate: to its very
> restricted avatar Number readFrom:
>
> example of non smart readFrom:
>         Number readFrom: '1+1'.
>         Number readFrom: 'Float pi / 5 sin * 30'.
>
> Of course, you gotta trust your users then, not very secure...
>
> Nicolas

That sounds like Java talk. :)  I think the most powerful languages
(Lisp and Smalltalk) are powerful exactly because they *do* trust
their users.

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Philippe Marschall
2008/1/13, Jason Johnson <[hidden email]>:

> On Jan 8, 2008 9:43 PM, nicolas cellier <[hidden email]> wrote:
> >
> > However, I always preferred the power of Compiler evaluate: to its very
> > restricted avatar Number readFrom:
> >
> > example of non smart readFrom:
> >         Number readFrom: '1+1'.
> >         Number readFrom: 'Float pi / 5 sin * 30'.
> >
> > Of course, you gotta trust your users then, not very secure...
> >
> > Nicolas
>
> That sounds like Java talk. :)  I think the most powerful languages
> (Lisp and Smalltalk) are powerful exactly because they *do* trust
> their users.

Rigth. This is especially cool, if your user is someone who sends you
a SOAP message. Trusting him passing the whatever he sends you through
the compiler seems like the best way to go.

Cheers
Philippe

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Jason Johnson-5
If you're going to interface with external systems then obviously you
need security, but we don't need the Squeak environment to protect us
from ourselves anymore then it does now (well, immutability would be
nice).  There are plenty of systems out there that assume the people
using them are complete tools not to be trusted.

On Jan 13, 2008 3:24 PM, Philippe Marschall
<[hidden email]> wrote:

> 2008/1/13, Jason Johnson <[hidden email]>:
>
> > On Jan 8, 2008 9:43 PM, nicolas cellier <[hidden email]> wrote:
> > >
> > > However, I always preferred the power of Compiler evaluate: to its very
> > > restricted avatar Number readFrom:
> > >
> > > example of non smart readFrom:
> > >         Number readFrom: '1+1'.
> > >         Number readFrom: 'Float pi / 5 sin * 30'.
> > >
> > > Of course, you gotta trust your users then, not very secure...
> > >
> > > Nicolas
> >
> > That sounds like Java talk. :)  I think the most powerful languages
> > (Lisp and Smalltalk) are powerful exactly because they *do* trust
> > their users.
>
> Rigth. This is especially cool, if your user is someone who sends you
> a SOAP message. Trusting him passing the whatever he sends you through
> the compiler seems like the best way to go.
>
> Cheers
> Philippe
>
>

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

stephane ducasse
In reply to this post by Zulq Alam-2
since parseString: is a new message, I would suggest the following:

- write a couple of Sunit tests
- check that your methods work well with subclasses
- publish the code on SqueakSource and add an entry to mantis
- announce it to the list

Stef


> Others might find this useful. Especially those looking for the  
> equivalent to Integer.parseInt in Java. What would be a good way for  
> making these types of changes available?
>
> Thanks,
> Zulq.
>
> Damien Cassou wrote:
>> You should use #readExactlyFrom:
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Zulq Alam-2
In reply to this post by Damien Cassou-3
Ok, I've done this and added a change set including an implementation
and unit tests (http://bugs.squeak.org/view.php?id=6859).

Thanks,
Zulq.

Damien Cassou wrote:
> On Jan 9, 2008 12:24 PM, Zulq Alam <[hidden email]> wrote:
>> Others might find this useful. Especially those looking for the
>> equivalent to Integer.parseInt in Java. What would be a good way for
>> making these types of changes available?
>
> Submit a bug report on mantis.
>


Reply | Threaded
Open this post in threaded view
|

Re: (Integer readFrom: 'abc' readStream) = 0

Zulq Alam-2
In reply to this post by stephane ducasse
Did the SUnit tests and added some explicit tests for Integer subclasses
and added these as a change set to the mantis entry I created
(http://bugs.squeak.org/view.php?id=6859).

Do you really think I should create a SqueakSource project for this
change? It's only a couple of methods and corresponding unit tests. Or,
did you have something else in mind.

Also, To create a Monticello package I will have to move the methods to
*PackageName- categories. Unless, there is a way to include arbitrary
change sets in Moniticello versions?

Thanks,
Zulq.


stephane ducasse wrote:

> since parseString: is a new message, I would suggest the following:
>
> - write a couple of Sunit tests
> - check that your methods work well with subclasses
> - publish the code on SqueakSource and add an entry to mantis
> - announce it to the list
>
> Stef
>
>
>> Others might find this useful. Especially those looking for the
>> equivalent to Integer.parseInt in Java. What would be a good way for
>> making these types of changes available?
>>
>> Thanks,
>> Zulq.
>>
>> Damien Cassou wrote:
>>> You should use #readExactlyFrom:
>>
>>
>>
>
>