parsing a file / stream API advice

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

parsing a file / stream API advice

Daniel Lyons
This is an OO design question.

For my task, I have some objects and a particular file format that encodes them. I want to be able to read the file and create those objects. The Stream API seems like the right way to do this, but I'm not sure how to encapsulate my code. I see these options:

 • Create a new class (subclass of Object) that implements #next to return the next object in some underlying stream.

Pro: very simple, one place with all the code. Con: what about the rest of the Stream and/or Collection APIs? Is it wise to delegate everything else to the underlying stream with #doesNotUnderstand:?

 • Create a new class, subclass of Stream, that implements #next like the above.

Pro: still pretty simple, not sure what is needed to implement the API completely (I did add a method #atEnd). Con: not sure if more methods are missing; unclear about initialization (overrode class>>#on: to call #basicNew). This seems close to the right approach but I'm unsure.

 • Create a method #nextFoo on the existing Stream class.

Pro: very simple—no new class. Con: nextFoo doesn't integrate well with the rest of the API (#do: for instance), not sure this is clean or wise.

 • Ignore the Stream classes altogether.

Pro: No chance of misundestanding. :) Con: everything else.

Advice?

Thanks for your time,


Daniel Lyons




Reply | Threaded
Open this post in threaded view
|

Re: parsing a file / stream API advice

Sven Van Caekenberghe-2
Hi Daniel,

I am not sure that there is any right answer. If you want to see examples, you can look how I did it in NeoCSV, NeoJSON or STON. They are all similar, but there are small differences.

You should do what feels best to you. Object design is (much more) about messaging that about class hierarchies. If some object understands the messages that another object wants to send it, then is compatible, independent of class hierarchy. It only makes sense to subclass if you gain something, like an implementation and if the superclass was designed to be subclasses. Often you can just implement a couple of messages (say, a small part of the stream protocol) and your object can be used (say, pass as a stream).

It also makes sense to reuse message selectors for similar behaviour. Most of my parsers understand #next, #atEnd, #close, #upToEnd - it helps other to immediately understand what you mean.

HTH,

Sven

> On 18 Jan 2015, at 06:11, Daniel Lyons <[hidden email]> wrote:
>
> This is an OO design question.
>
> For my task, I have some objects and a particular file format that encodes them. I want to be able to read the file and create those objects. The Stream API seems like the right way to do this, but I'm not sure how to encapsulate my code. I see these options:
>
> • Create a new class (subclass of Object) that implements #next to return the next object in some underlying stream.
>
> Pro: very simple, one place with all the code. Con: what about the rest of the Stream and/or Collection APIs? Is it wise to delegate everything else to the underlying stream with #doesNotUnderstand:?
>
> • Create a new class, subclass of Stream, that implements #next like the above.
>
> Pro: still pretty simple, not sure what is needed to implement the API completely (I did add a method #atEnd). Con: not sure if more methods are missing; unclear about initialization (overrode class>>#on: to call #basicNew). This seems close to the right approach but I'm unsure.
>
> • Create a method #nextFoo on the existing Stream class.
>
> Pro: very simple—no new class. Con: nextFoo doesn't integrate well with the rest of the API (#do: for instance), not sure this is clean or wise.
>
> • Ignore the Stream classes altogether.
>
> Pro: No chance of misundestanding. :) Con: everything else.
>
> Advice?
>
> Thanks for your time,
>
> —
> Daniel Lyons
>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: parsing a file / stream API advice

Ben Coman
In reply to this post by Daniel Lyons
Daniel,  I don't have a definitive answer for you.  I took an interest to browse what was built into Pharo (using Tools > Finder > Classes and searching for "stream" and also for "read") and looking at the hierarchy of several results it seems there is a mix.  I suppose the fall back position is "do the simplest thing that works."


On Sun, Jan 18, 2015 at 1:11 PM, Daniel Lyons <[hidden email]> wrote:
This is an OO design question.

For my task, I have some objects and a particular file format that encodes them. I want to be able to read the file and create those objects. The Stream API seems like the right way to do this, but I'm not sure how to encapsulate my code. I see these options:

 • Create a new class (subclass of Object) that implements #next to return the next object in some underlying stream.

Pro: very simple, one place with all the code. Con: what about the rest of the Stream and/or Collection APIs? Is it wise to delegate everything else to the underlying stream with #doesNotUnderstand:?


ImageReadWriter seems an example of this - but I don't think it delegates #doesNotUnderstand:  - it looks like it implements the full protocol in the "stream access" protocol. It has an instance variable /stream/ that it forwards                  t


 

 • Create a new class, subclass of Stream, that implements #next like the above.

Pro: still pretty simple, not sure what is needed to implement the API completely (I did add a method #atEnd). Con: not sure if more methods are missing; unclear about initialization (overrode class>>#on: to call #basicNew). This seems close to the right approach but I'm unsure.

 • Create a method #nextFoo on the existing Stream class.


JPEGReadStream and TxCharacterStream seem examples of this.  

 cheers -ben



Pro: very simple—no new class. Con: nextFoo doesn't integrate well with the rest of the API (#do: for instance), not sure this is clean or wise.

 • Ignore the Stream classes altogether.

Pro: No chance of misundestanding. :) Con: everything else.

Advice?

Thanks for your time,


Daniel Lyons





Reply | Threaded
Open this post in threaded view
|

Re: parsing a file / stream API advice

jfabry
In reply to this post by Daniel Lyons
Hi Daniel,

I have disclaimers as the 2 previous responses, this is my feeling about the matter. :-)

I would prefer to think purely in terms of the API that you want to use when reading the file, and have that clear and explicit. So do NOT subclass Stream nor do a class extension with #nextFoo. I would think in terms of the Stream API when doing that, and reuse as many message names as possible, because it is a fairly ‘standard’ API. So: option 1, without the use of doesNotUnderstand.

> On Jan 18, 2015, at 06:11, Daniel Lyons <[hidden email]> wrote:
>
> This is an OO design question.
>
> For my task, I have some objects and a particular file format that encodes them. I want to be able to read the file and create those objects. The Stream API seems like the right way to do this, but I'm not sure how to encapsulate my code. I see these options:
>
> • Create a new class (subclass of Object) that implements #next to return the next object in some underlying stream.
>
> Pro: very simple, one place with all the code. Con: what about the rest of the Stream and/or Collection APIs? Is it wise to delegate everything else to the underlying stream with #doesNotUnderstand:?
>
> • Create a new class, subclass of Stream, that implements #next like the above.
>
> Pro: still pretty simple, not sure what is needed to implement the API completely (I did add a method #atEnd). Con: not sure if more methods are missing; unclear about initialization (overrode class>>#on: to call #basicNew). This seems close to the right approach but I'm unsure.
>
> • Create a method #nextFoo on the existing Stream class.
>
> Pro: very simple—no new class. Con: nextFoo doesn't integrate well with the rest of the API (#do: for instance), not sure this is clean or wise.
>
> • Ignore the Stream classes altogether.
>
> Pro: No chance of misundestanding. :) Con: everything else.
>
> Advice?
>
> Thanks for your time,
>
> —
> Daniel Lyons
>
>
>
>
>



---> Save our in-boxes! http://emailcharter.org <---

Johan Fabry   -   http://pleiad.cl/~jfabry
PLEIAD lab  -  Computer Science Department (DCC)  -  University of Chile


Reply | Threaded
Open this post in threaded view
|

Re: parsing a file / stream API advice

Daniel Lyons
Thanks to all of you for the advice!

> On Jan 18, 2015, at 9:31 AM, Johan Fabry <[hidden email]> wrote:
>
> Hi Daniel,
>
> I have disclaimers as the 2 previous responses, this is my feeling about the matter. :-)
>
> I would prefer to think purely in terms of the API that you want to use when reading the file, and have that clear and explicit. So do NOT subclass Stream nor do a class extension with #nextFoo. I would think in terms of the Stream API when doing that, and reuse as many message names as possible, because it is a fairly ‘standard’ API. So: option 1, without the use of doesNotUnderstand.
>
>> On Jan 18, 2015, at 06:11, Daniel Lyons <[hidden email]> wrote:
>>
>> This is an OO design question.
>>
>> For my task, I have some objects and a particular file format that encodes them. I want to be able to read the file and create those objects. The Stream API seems like the right way to do this, but I'm not sure how to encapsulate my code. I see these options:
>>
>> • Create a new class (subclass of Object) that implements #next to return the next object in some underlying stream.
>>
>> Pro: very simple, one place with all the code. Con: what about the rest of the Stream and/or Collection APIs? Is it wise to delegate everything else to the underlying stream with #doesNotUnderstand:?
>>
>> • Create a new class, subclass of Stream, that implements #next like the above.
>>
>> Pro: still pretty simple, not sure what is needed to implement the API completely (I did add a method #atEnd). Con: not sure if more methods are missing; unclear about initialization (overrode class>>#on: to call #basicNew). This seems close to the right approach but I'm unsure.
>>
>> • Create a method #nextFoo on the existing Stream class.
>>
>> Pro: very simple—no new class. Con: nextFoo doesn't integrate well with the rest of the API (#do: for instance), not sure this is clean or wise.
>>
>> • Ignore the Stream classes altogether.
>>
>> Pro: No chance of misundestanding. :) Con: everything else.
>>
>> Advice?
>>
>> Thanks for your time,
>>
>> —
>> Daniel Lyons
>>
>>
>>
>>
>>
>
>
>
> ---> Save our in-boxes! http://emailcharter.org <---
>
> Johan Fabry   -   http://pleiad.cl/~jfabry
> PLEIAD lab  -  Computer Science Department (DCC)  -  University of Chile
>
>


Daniel Lyons