PrintConverter not extensible

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

PrintConverter not extensible

Rob Vens-2
I do not know if others have this problem, but I find it hard to
extend the class PrintConverter.
For example I have a Currency class, which overrides the class method for:
PrintConverter class>>for: aSymbol
   ...
        aSymbol == #currency ifTrue: [^converter initForCurrency].
   ...

and:
PrintConverter class>>for: aSymbol withFormatString: aString
   ...
        aSymbol == #currency
                ifTrue: [^self new initForCurrencyWithFormat: aString].
   ...

However, other packages I have also need to add things to these
methods, which creates an override hell, not to mention that
publishing a package with overrides is not allowed.
So, did anyone find a solution for this, and could the class maybe be
improved to allow extensions from applications?

Reply | Threaded
Open this post in threaded view
|

Re: PrintConverter not extensible

Dennis smith-4
No real help from me -- but I looked at PrintConverter, and wrote my own
set of converter classes (a whole set of them) -- and treat all my fields
on GUI's as strings and do my own conversions in my subclass of
AspectConverter.
Took a bit of time to get started, but in the long run it was simpler I
think.

Unfortunately my classes are tied pretty strongly into other concepts in
our applications
but basically I had one class for each data type, and dispatched it from
the class side.

Rob Vens wrote:

> I do not know if others have this problem, but I find it hard to
> extend the class PrintConverter.
> For example I have a Currency class, which overrides the class method
> for:
> PrintConverter class>>for: aSymbol
>   ...
>     aSymbol == #currency ifTrue: [^converter initForCurrency].
>   ...
>
> and:
> PrintConverter class>>for: aSymbol withFormatString: aString
>   ...
>     aSymbol == #currency
>         ifTrue: [^self new initForCurrencyWithFormat: aString].
>   ...
>
> However, other packages I have also need to add things to these
> methods, which creates an override hell, not to mention that
> publishing a package with overrides is not allowed.
> So, did anyone find a solution for this, and could the class maybe be
> improved to allow extensions from applications?
>

--
Dennis Smith                         +1 416.798.7948
Cherniak Software Development Corporation   Fax: +1 416.798.0948
509-2001 Sheppard Avenue East        [hidden email]
Toronto, ON M2J 4Z8              sip:[hidden email]
Canada         http://www.CherniakSoftware.com
Entrance off Yorkland Blvd south of Sheppard Ave east of the DVP

Reply | Threaded
Open this post in threaded view
|

Re: PrintConverter not extensible

davidbuck
In reply to this post by Rob Vens-2
This sounds like a job for Pragmas.

In PrintConverter, define a new class method:

formatPragma
    <pragmas: #class>
    ^#(#format:send:)

Now, in the PrintConverter >> for:withFormatString: method, add the
following before the last line:

    (Pragma allNamed: #format:send: in: self class) do:
        [:pragma |
        pragma withArgumentsDo:
            [:formatString :selector | aSymbol == formatString ifTrue:
[^self new perform: selector with: aString]]].

Now, you can extend the PrintConverter to your heart's content.  Any
time you want to add a new converter, extend PrintConverter and add  a
method like this:

sampleExtendedFormat
    <format: #sample send: #initForSample:>

Now, define initForSample: as an extension as well and get it to do the
formatting you want.

David Buck
Simberon Inc.
www.simberon.com

Rob Vens wrote:

> I do not know if others have this problem, but I find it hard to
> extend the class PrintConverter.
> For example I have a Currency class, which overrides the class method
> for:
> PrintConverter class>>for: aSymbol
>   ...
>     aSymbol == #currency ifTrue: [^converter initForCurrency].
>   ...
>
> and:
> PrintConverter class>>for: aSymbol withFormatString: aString
>   ...
>     aSymbol == #currency
>         ifTrue: [^self new initForCurrencyWithFormat: aString].
>   ...
>
> However, other packages I have also need to add things to these
> methods, which creates an override hell, not to mention that
> publishing a package with overrides is not allowed.
> So, did anyone find a solution for this, and could the class maybe be
> improved to allow extensions from applications?
>
>

Reply | Threaded
Open this post in threaded view
|

Re: PrintConverter not extensible

Rob Vens-2
Thanks, David, I should have thought of that! I will try it out
immediately. I must admit that employing the pragmas has been
neglected by me so this seems a good reason to do just that.

2007/4/15, David Buck <[hidden email]>:

> This sounds like a job for Pragmas.
>
> In PrintConverter, define a new class method:
>
> formatPragma
>     <pragmas: #class>
>     ^#(#format:send:)
>
> Now, in the PrintConverter >> for:withFormatString: method, add the
> following before the last line:
>
>     (Pragma allNamed: #format:send: in: self class) do:
>         [:pragma |
>         pragma withArgumentsDo:
>             [:formatString :selector | aSymbol == formatString ifTrue:
> [^self new perform: selector with: aString]]].
>
> Now, you can extend the PrintConverter to your heart's content.  Any
> time you want to add a new converter, extend PrintConverter and add  a
> method like this:
>
> sampleExtendedFormat
>     <format: #sample send: #initForSample:>
>
> Now, define initForSample: as an extension as well and get it to do the
> formatting you want.
>
> David Buck
> Simberon Inc.
> www.simberon.com
>
> Rob Vens wrote:
> > I do not know if others have this problem, but I find it hard to
> > extend the class PrintConverter.
> > For example I have a Currency class, which overrides the class method
> > for:
> > PrintConverter class>>for: aSymbol
> >   ...
> >     aSymbol == #currency ifTrue: [^converter initForCurrency].
> >   ...
> >
> > and:
> > PrintConverter class>>for: aSymbol withFormatString: aString
> >   ...
> >     aSymbol == #currency
> >         ifTrue: [^self new initForCurrencyWithFormat: aString].
> >   ...
> >
> > However, other packages I have also need to add things to these
> > methods, which creates an override hell, not to mention that
> > publishing a package with overrides is not allowed.
> > So, did anyone find a solution for this, and could the class maybe be
> > improved to allow extensions from applications?
> >
> >
>
>

Reply | Threaded
Open this post in threaded view
|

Re: PrintConverter not extensible

davidbuck
Just to clarify, these are all class methods except for initFotSample:
which is an instance method.

David Buck

Rob Vens wrote:

> Thanks, David, I should have thought of that! I will try it out
> immediately. I must admit that employing the pragmas has been
> neglected by me so this seems a good reason to do just that.
>
> 2007/4/15, David Buck <[hidden email]>:
>> This sounds like a job for Pragmas.
>>
>> In PrintConverter, define a new class method:
>>
>> formatPragma
>>     <pragmas: #class>
>>     ^#(#format:send:)
>>
>> Now, in the PrintConverter >> for:withFormatString: method, add the
>> following before the last line:
>>
>>     (Pragma allNamed: #format:send: in: self class) do:
>>         [:pragma |
>>         pragma withArgumentsDo:
>>             [:formatString :selector | aSymbol == formatString ifTrue:
>> [^self new perform: selector with: aString]]].
>>
>> Now, you can extend the PrintConverter to your heart's content.  Any
>> time you want to add a new converter, extend PrintConverter and add  a
>> method like this:
>>
>> sampleExtendedFormat
>>     <format: #sample send: #initForSample:>
>>
>> Now, define initForSample: as an extension as well and get it to do the
>> formatting you want.
>>
>> David Buck
>> Simberon Inc.
>> www.simberon.com
>>
>> Rob Vens wrote:
>> > I do not know if others have this problem, but I find it hard to
>> > extend the class PrintConverter.
>> > For example I have a Currency class, which overrides the class method
>> > for:
>> > PrintConverter class>>for: aSymbol
>> >   ...
>> >     aSymbol == #currency ifTrue: [^converter initForCurrency].
>> >   ...
>> >
>> > and:
>> > PrintConverter class>>for: aSymbol withFormatString: aString
>> >   ...
>> >     aSymbol == #currency
>> >         ifTrue: [^self new initForCurrencyWithFormat: aString].
>> >   ...
>> >
>> > However, other packages I have also need to add things to these
>> > methods, which creates an override hell, not to mention that
>> > publishing a package with overrides is not allowed.
>> > So, did anyone find a solution for this, and could the class maybe be
>> > improved to allow extensions from applications?
>> >
>> >
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: PrintConverter not extensible

Travis Griggs-3
On Apr 15, 2007, at 7:36, David Buck wrote:

Just to clarify, these are all class methods except for initFotSample: which is an instance method.

David Buck

Rob Vens wrote:
Thanks, David, I should have thought of that! I will try it out
immediately. I must admit that employing the pragmas has been
neglected by me so this seems a good reason to do just that.

2007/4/15, David Buck <[hidden email]>:
This sounds like a job for Pragmas.

In PrintConverter, define a new class method:

formatPragma
    <pragmas: #class>
    ^#(#format:send:)

Now, in the PrintConverter >> for:withFormatString: method, add the
following before the last line:

    (Pragma allNamed: #format:send: in: self class) do:
        [:pragma |
        pragma withArgumentsDo:
            [:formatString :selector | aSymbol == formatString ifTrue:
[^self new perform: selector with: aString]]].

Now, you can extend the PrintConverter to your heart's content.  Any
time you want to add a new converter, extend PrintConverter and add  a
method like this:

sampleExtendedFormat
    <format: #sample send: #initForSample:>

Now, define initForSample: as an extension as well and get it to do the
formatting you want.

David Buck
Simberon Inc.
www.simberon.com

Rob Vens wrote:
> I do not know if others have this problem, but I find it hard to
> extend the class PrintConverter.
> For example I have a Currency class, which overrides the class method
> for:
> PrintConverter class>>for: aSymbol
>   ...
>     aSymbol == #currency ifTrue: [^converter initForCurrency].
>   ...
>
> and:
> PrintConverter class>>for: aSymbol withFormatString: aString
>   ...
>     aSymbol == #currency
>         ifTrue: [^self new initForCurrencyWithFormat: aString].
>   ...
>
> However, other packages I have also need to add things to these
> methods, which creates an override hell, not to mention that
> publishing a package with overrides is not allowed.
> So, did anyone find a solution for this, and could the class maybe be
> improved to allow extensions from applications?

This is cool David. Indeed.

Looking it at, it seems one could go even farther. Rather than having the class side sampleExtendedFormat method... I think I would just add an instance tag (pragma) to the initForSample: method, and search for and call that directly at the end of for:withFormatString: You'd have half as many methods and a more direct linkage.

This is indeed a neat way to use tagged methods. That said though, I was horrified by the method in the first place. It is a huge case statement. And what we seem to be doing here is making the case statement extensible. Even when we use tags to make it pluggable, it's still a case statement.

There's a sense of "use the method Luke" that I find myself mumbling looking at this code. Rather than

PrintConverter for: #currency withFormatString: 'blah'

wouldn't it just be better to do:

PrintConverter currency withFormatString: 'blah'.

I admit to not messing directly with these things often, so maybe I'm missing something. But this seems far better. It is instantly "extendible", because you just add a new method for creating PrintConverters of a new type. And it does so by getting rid of indirection, removing tags (pragmas), removing case statements, etc. You could put this pattern in place without even having to modify the existing thing.

After that... one might argue that it would be better to just have typified subclasses. So that in the end you can send:

StringConverter withFormatString: 'blah'.

There is no "technical" reason one was to go the subclass route, because the Converters are just bags of blocks with state closed directly in the initMethods. But even with empty subclasses, I think the interface would be that much clearer, the possibilities are higher (you could indeed add instance state), and the code you input to interface with them is less and more direct.

I'm ambivalent on the subclasses thing, but I do think that it's better to send messages, instead of passing symbols that look kind of like the messages they're going to turn into, but not exactly.

--
Travis Griggs
Objologist
My Other Machine runs OSX. But then... so does this one.