[squeak-dev] My view on Traits

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 | Next >

[squeak-dev] Re: My view on Traits

by Klaus D. Witzel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, 17 May 2008 10:12:47 +0200, Andreas Raab wrote:

> Klaus D. Witzel wrote:
>> I think you can easily judge for yourself whether or not a system gives  
>> you multiple inheritance (MI):
>>  o in Smalltalk every class has at most one superclass
>> o every MI class has at least two superclasses
>> o in Smalltalk a method can send to self or super
>> o a method in an MI class can choose to which super it sends
>>  Compare Squeak's traits to these statements ...
>
> I don't think this is a particularly good definition of MI but the above  
> certainly applies to traits: When a class uses a trait it certainly has  
> multiple superclasses for all its observable behavior;

Sure, one can view it like that indeed (in particular *if* Trait *would*  
inherit from ClassDescription ;)

> when the method in the trait is changed the behavior in the class  
> changes unless it has been reimplemented locally, which is the behavior  
> of superclasses.
>
> For the "super sends" the only reason for aliasing in traits that I'm  
> aware of is to get access for a trait user to a "particular version of  
> the superclass method". Even in the earliest papers there was an example  
> about a "colored rectangle" derived from TColor and TRectangle used  
> aliases to get to specific implementations in its "super classes".

Right. To be able to mimic "which super is meant" one has to carefully  
handcraft composition rules and invent aliases in order to arrive at a  
conflict-free situation (hopefully maintainable by the next hacker/user ;)  
And since a user (*and* its superclasses) can have own methods,  
conflict-free can mean cause of conflicts from both sides.

This (potential usability/mutual influence) is one of the reasons that I'm  
interested in Trygve's work on roles (i.e. arrive at traits which are  
independent of potential users).

> In other words, even though it may be called a little differently, the  
> concepts that you describe are all present. Which is why traits are  
> generally treated as a form of MI.

Which is why it *can* be confusing ;)

> Cheers,
>    - Andreas
>



Re: [squeak-dev] A criticism of the Nile paper (was Re: My view on Traits)

by stephane ducasse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks victor.
This is the point.

I stopped to comment these kind of "counting less classes = better"  
argument.
And stop to consider all the feedback useful: we changed nile because  
the first design
was not good. If people like the Stream hierarchy, they can just keep  
it.
I think that we are focusing on the wrong problem and at the end
frankly I believe that we did our job and pretty well. We will continue
and we want to build collection hierarchy based on traits, but don't  
worry
this will not be in Squeak.

Stef

On May 17, 2008, at 3:28 AM, Victor Rodriguez wrote:

> Hi,
>
> On Fri, May 16, 2008 at 4:38 PM, Andreas Raab <andreas.raab@...>  
> wrote:
> ...
>> It is interesting to do a quick check to see how much this might  
>> change
>> matters: First, combining these three classes into one means that  
>> the traits
>> version has now twice the number of entities vs. the non-traits  
>> version (3
>> vs 6). This view is also supported by counting the "backward  
>> compatible"
>
> Less entities are not necessarily better than more, as I´m sure you
> know.  Generally, more classes with a clear responsibility are better
> than less, harder to understand, classes.
>
>> part of Figure 12 (which is directly comparable with the Squeak  
>> version)
>> which results in 11 classes and traits (compared to 5 classes in  
>> Squeak).
>>
>> Next, if we take the total number of methods in these three classes:
>>
>> ReadStream selectors size +
>> WriteStream selectors size +
>> ReadWriteStream selectors size
>> -----------------
>> 68
>>
>> (the measure was taken in 3.9 to be roughly comparable with the  
>> paper and
>> I'm not sure why the paper claims 55 methods) and compare this with  
>> the
>> number of unique selectors (discounting all re-implemented methods):
>>
>> (Set withAll:
>>   (ReadStream selectors asArray),
>>   (WriteStream selectors asArray),
>>   (ReadWriteStream selectors asArray)) size
>> -------------------
>> 59
>>
>> What we get is 15% improvement *minimum* by folding these three  
>> classes
>> (very likely more if one looks in detail).
>>
>> Next, let's look at "canceled methods" (those that use  
>> #shouldNotImplement).
>> The paper lists 2 canceled methods which happen to be  
>> WriteStream>>next and
>> ReadStream>>nextPut:. And of course those wouldn't exist in a
>> single-inheritance implementation either. Etc.
>>
>> In other words, the measures change *dramatically* as soon as we  
>> apply the
>> original idea regardless of whether traits are used or not. Which  
>> speaks
>> clearly for the original idea of folding these three classes into  
>> one but
>> concluding that traits have anything to do with it would require a  
>> very
>> different comparison.
>>
>> If the paper wants to make any claims regarding traits, it really  
>> needs to
>> distinguish improvements that are due to traits from general  
>> improvements
>> (i.e., improvements that are just as applicable to single-inheritance
>> implementations). Otherwise it is comparing apples to oranges and  
>> can't be
>> taken seriously in this regard.
>
> But there *are* limits to what you can achieve with single
> inheritance.  It is not very hard to come up with an example:
>
> The Magnitude class is the perfect candidate for being converted into
> a trait, if you ask me.  Here is its class comment:
>
>    I'm the abstract class Magnitude that provides common protocol for
> objects that have
>    the ability to be compared along a linear dimension, such as  
> dates or times.
>    Subclasses of Magnitude include Date, ArithmeticValue, and Time,
> as well as
>    Character and LookupKey.
>
>    My subclasses should implement
>      < aMagnitude
>      = aMagnitude
>      hash
>
> Subclasses of Magnitude, by implementing #< #= #hash, gain methods #<=
> #> #>= #between:and: #hashMappedBy: #max: #min: #min:max:.  The
> subclasses of Magnitude are Number, Character, DateAndTime, etc.
>
> String does not subclass Magnitude, it subclasses ArrayedCollection,
> and yet it does implement #< #= and #hash.  It could clearly benefit
> from using Magnitude as a trait (indeed, it does implement
> #hashMappedBy: exactly as Magnitude).
>
> Having traits like Magnitude leave you more options to define a better
> inheritance hierarchy.
>
> Saludos,
>
> Víctor Rodríguez.
>
>> Cheers,
>> - Andreas
>>
>>
>>
>
>



Re: [squeak-dev] A criticism of the Nile paper (was Re: My view on Traits)

by Damien Cassou-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Andreas,

thank you for your comment. I'm not sure what is exactly the design
you propose. However, it seems you won't be able to cleanly implement
FileStream, History and Decoder, do you? Could you please provide a
set of diagrams so that we can compare apples and apples :-)?

Have a nice week-end

--
Damien Cassou
Peter von der Ahé: «I'm beginning to see why Gilad wished us good
luck». (http://blogs.sun.com/ahe/entry/override_snafu)


[squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Andreas Raab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

stephane ducasse wrote:
> Thanks victor.
> This is the point.
>
> I stopped to comment these kind of "counting less classes = better"
> argument.

The paper itself seems to have a different view on this. It states on
p.22 "The first metric indicates that Nile has *only* one more entity
(class/trait) than the Squeak implementation." (emphasis mine) So
obviously the author(s) of the paper seem to feel that having "only" one
more entity is something quite desirable. Which is why I was pointing
out that this measure is incorrect and the correct statement should be
"Nile has twice as many entities when compared to a corresponding Squeak
implementation" regardless of its interpretation.

> And stop to consider all the feedback useful: we changed nile because
> the first design
> was not good. If people like the Stream hierarchy, they can just keep it.

I like Nile. I think it contains some good ideas. But I don't think that
much of that is due to the use of traits and I won't let people get away
with making claims (in a journal paper no less) that have no basis in
reality. In particular when it comes to metrics - we can disagree on
whether the structure is more or less easily understood when using
traits but I don't think we should disagree on how to count the number
of classes and traits in Nile or a corresponding Squeak implementation.

> I think that we are focusing on the wrong problem and at the end
> frankly I believe that we did our job and pretty well. We will continue
> and we want to build collection hierarchy based on traits, but don't worry
> this will not be in Squeak.

Sure. Whatever. If you want to evade the discussions by running away, be
my guest. Wrong data is wrong data though and if you keep comparing
apples and oranges other people will ask the same questions.

Cheers,
   - Andreas



Re: [squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Damien Cassou-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, May 17, 2008 at 2:02 PM, Andreas Raab <andreas.raab@...> wrote:
> Wrong data is wrong data though and if you keep comparing apples and
> oranges other people will ask the same questions.


We based our comparison on something that existed for a long time.
Moreover, ANSI defines a set of protocols that we wanted to reflect in
our implementation. Now, you propose something new and probably
interesting in absence of traits. If I understand correctly, your
proposal does not follow ANSI. This is not a problem, but we tried to
follow it when we designed Nile. I'm afraid that comparing Nile with
your design would lead to compare apples and bananas :-). But still,
I'm very interested in your proposal. It would be cool if you could
provide diagrams and/or implementation.


--
Damien Cassou
Peter von der Ahé: «I'm beginning to see why Gilad wished us good
luck». (http://blogs.sun.com/ahe/entry/override_snafu)


[squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Andreas Raab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Damien Cassou wrote:
> thank you for your comment. I'm not sure what is exactly the design
> you propose. However, it seems you won't be able to cleanly implement
> FileStream, History and Decoder, do you? Could you please provide a
> set of diagrams so that we can compare apples and apples :-)?

I'll think about it. The main problem with the paper is that it takes
the triad ReadStream, WriteStream, ReadWriteStream and replaces those
with CollectionStream and then lists a bunch of numbers that I simply
cannot recreate. For example, how did you come up with the "number of
methods" in Table 6? This doesn't compute for me at all - neither if I
look at only those three classes, nor when I look at the number of
inherited stream methods.

Also, how do you decide whether "methods are implemented too high" in
the hierarchy? For table 6, which methods did you consider to be
implemented too high and are these counted in the total number of
methods (which I doubt since the total number of methods is too small to
include methods in superclasses so by definition it shouldn't count those).

About FileStream, History and Decoder: Please provide a definition of
"cleanly implement" so that I can see if a solution to the problem
exists. FileStream and Decoder look fairly straightforward though so
unless you have a very restricted definition of "clean" I'm pretty sure
I can come up with something.

Cheers,
   - Andreas



Re: [squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Damien Cassou-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, May 17, 2008 at 2:27 PM, Andreas Raab <andreas.raab@...> wrote:
> I'll think about it. The main problem with the paper is that it takes the
> triad ReadStream, WriteStream, ReadWriteStream and replaces those with
> CollectionStream and then lists a bunch of numbers that I simply cannot
> recreate. For example, how did you come up with the "number of methods" in
> Table 6? This doesn't compute for me at all - neither if I look at only
> those three classes, nor when I look at the number of inherited stream
> methods.


Please have a look at the NSMetrics class. Here, you have the methods
which generate the tables and their numbers. If you find any problem
with the algorithms, please tell me.


> Also, how do you decide whether "methods are implemented too high" in the
> hierarchy?


The algorithm is in NSMetrics too.


> For table 6, which methods did you consider to be implemented too
> high and are these counted in the total number of methods (which I doubt
> since the total number of methods is too small to include methods in
> superclasses so by definition it shouldn't count those).
>
> About FileStream, History and Decoder: Please provide a definition of
> "cleanly implement" so that I can see if a solution to the problem exists.
> FileStream and Decoder look fairly straightforward though so unless you have
> a very restricted definition of "clean" I'm pretty sure I can come up with
> something.

I have no definition of "cleanly implemented". I guess I would
consider your approach clean if you avoid methods implemented too high
and duplicated code. It is also important that you try to provide the
same features as Squeak and Nile do. The last thing I'm thinking about
right now is interface pollution: please avoid adding writing behavior
(like #nextPut) to read-only streams like Random and Decoder. The same
goes for positioning (with position:) and History.

--
Damien Cassou
Peter von der Ahé: «I'm beginning to see why Gilad wished us good
luck». (http://blogs.sun.com/ahe/entry/override_snafu)


[squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Andreas Raab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Damien Cassou wrote:
> Please have a look at the NSMetrics class. Here, you have the methods
> which generate the tables and their numbers. If you find any problem
> with the algorithms, please tell me.

Excellent, thanks. I had never seen NSMetrics before. Is there a
particular version of Nile that should be used for those measures? I
tried 0.9.5 (the latest published universe version available in 3.10)
and it blows up, first because there is no trait NSTCollectionStream and
later because it sends #overridesSelectors which isn't implemented anywhere.

Cheers,
   - Andreas


Re: [squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Damien Cassou-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, May 17, 2008 at 3:40 PM, Andreas Raab <andreas.raab@...> wrote:

> Damien Cassou wrote:
>>
>> Please have a look at the NSMetrics class. Here, you have the methods
>> which generate the tables and their numbers. If you find any problem
>> with the algorithms, please tell me.
>
> Excellent, thanks. I had never seen NSMetrics before. Is there a particular
> version of Nile that should be used for those measures? I tried 0.9.5 (the
> latest published universe version available in 3.10) and it blows up, first
> because there is no trait NSTCollectionStream and later because it sends
> #overridesSelectors which isn't implemented anywhere.

I'm sorry. I haven't updated the universe package for some time.
Please use SqueakSource and load Nile-All. This package depends on
other required package and contains NSMetrics.

--
Damien Cassou
Peter von der Ahé: «I'm beginning to see why Gilad wished us good
luck». (http://blogs.sun.com/ahe/entry/override_snafu)


Re: [squeak-dev] Re: A criticism of the Nile paper

by Colin Putney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 16-May-08, at 5:01 PM, Craig Latta wrote:

>     Yes. As far as using streams as an example, I never understood  
> why support for write-only streams was ever needed. What's wrong  
> with just assuming all streams are readable? Then this classic  
> dilemma just goes away. It seems to me that whoever wrote the first  
> internal streams implementation for Smalltalk simply got that part  
> wrong, and no one questioned it for a long time. I wouldn't make  
> this a primary motivating example for traits (hopefully there's a  
> better one).

Heh - I've long had nearly the opposite question: Why was support for  
read-write streams ever needed? I can't recall *ever* using it in my  
own code, nor encountering it in anyone else's.

The one exception, of course, is SocketStream, and I think it proves  
the rule. I've had to dig into that code to implement a missing  
feature, and let me tell you... it's complicated. I'd much rather have  
seen clients use two separate streams, or even wrap them in a  
DuplexStream if having a single object is that important.

Colin


[squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Andreas Raab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Damien Cassou wrote:
> I'm sorry. I haven't updated the universe package for some time.
> Please use SqueakSource and load Nile-All. This package depends on
> other required package and contains NSMetrics.

Okay, after loading this I understand better where the numbers come
from. First, a couple of comments on NSMetrics:
#methodsInClassAndMetaclass:methodListBlock: does a union of methods in
class and metaclass which looks a little questionable to me. I don't
think it matters here but it seems odd to count a method in class and
metaclass only once. The #numberOfReimplementedMethodsForClasses: also
has two problems in such that it does only look at methods overridden in
the direct superclass (so it doesn't find methods implemented in Stream
and overridden in ReadStream but not in PositionableStream) and that it
excludes the required selectors of traits but not those of superclasses
(i.e., self subclassResponsibility) which it should discount as well
(see note below on the metrics that are affected by it).

That said, we can now devise a comparison which is more appropriate for
a Nile vs. Squeak comparison. I've attached a simple class
InternalStream which as a subclass of PositionableStream implements the
same folding of ReadStream, WriteStream, and ReadWriteStream. I believe
it to be a fully functioning equivalent to NSCollectionStream. If we run
the design metrics using InternalStream instead of the three other
classes we end up with metrics that look like this (slightly reformatted
from the TeX output):

                                  Squeak  Nile (Squeak-Nile)/Squeak
Number of Classes And Traits        3      6          -100%
Number of Classes                   3      1            66%
Number of Methods                  39     33            15% [*1]
Number of Bytes                  1328   1078            18%
Number of Cancelled Methods         0      0             0%
Number of Reimplemented Methods    10      3            70% [*1]
Number of Methods Impl. Too High    0      0             0%

[*1] This includes 2 subclassResponsibilities in Squeak which should be
discounted as pointed out above.

The main differences are in the number of entities as well as in the
number of methods (overrides). Looking at it in detail it turns out that
the larger number of entities comes purely from the more fine-grained
structure of traits (only one class but five traits) and the larger
number of methods come from overrides where InternalStream has either
more efficient versions (#upTo: #next: #upToEnd) or needs to compensate
PositionableStream assuming that the position will be within its
readLimit (#position: #setToEnd #reset) or implements required
subclassResponsibilities (#atEnd, #contents).

It is interesting to see that the traits version can do without most of
those overrides although it isn't clear to me that this would remain a
lasting advantage. One could rewrite the Squeak collection hierarchy to
do without these overrides by relaxing the constraints on
PositionableStream and use more effective versions by default. This
would improve these metrics but I'm not sure it is in the spirit of the
Squeak collection hierarchy.

That said, I would also slightly refactor NSCollectionStream into, e.g.,

NSPositionableStream <NSTGettableStream + NSPuttableStream +
NSPositionableStream>
   NSCollectionStream

The idea in the above refactoring is to keep the "composition class"
(NSPositionableStream) separate from the "implementation class"
(NSCollectionStream). It really makes it easier to see what you've done
in NSCollectionStream and having a class used only to gather the traits
also makes it more clear that anything you'd implement at that level
really belongs into a trait and not into the class. It makes looking at
classes with traits almost bearable ;-)

Cheers,
   - Andreas

'From Squeak3.9.1 of 2 March 2008 [latest update: #7075] on 17 May 2008 at 1:19:35 pm'!
PositionableStream subclass: #InternalStream
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Collections-Streams'!
!InternalStream commentStamp: 'ar 5/17/2008 07:44' prior: 0!
Simple class combining ReadStream, WriteStream and ReadWriteStream.!


!InternalStream methodsFor: 'initialize' stamp: 'ar 5/17/2008 08:46'!
on: aCollection from: firstIndex to: lastIndex

        | len |
        collection := aCollection.
        readLimit := lastIndex > (len := collection size)
                                                ifTrue: [len]
                                                ifFalse: [lastIndex].
        position := firstIndex <= 1
                                ifTrue: [0]
                                ifFalse: [firstIndex - 1]! !


!InternalStream methodsFor: 'accessing' stamp: 'ar 5/17/2008 07:32'!
ascii! !

!InternalStream methodsFor: 'accessing' stamp: 'ar 5/17/2008 07:32'!
readStream
        "polymorphic with SequenceableCollection.  Return self"
        ^ self! !

!InternalStream methodsFor: 'accessing' stamp: 'ar 5/17/2008 07:39'!
size
        "Compatibility with other streams (e.g., FileStream)"
        ^readLimit := readLimit max: position! !

!InternalStream methodsFor: 'accessing' stamp: 'ar 5/17/2008 08:45'!
writeLimit
        ^collection size! !


!InternalStream methodsFor: 'reading' stamp: 'ar 5/17/2008 07:31'!
next
        "Primitive. Answer the next object in the Stream represented by the
        receiver. Fail if the collection of this stream is not an Array or a String.
        Fail if the stream is positioned at its end, or if the position is out of
        bounds in the collection. Optional. See Object documentation
        whatIsAPrimitive."

        <primitive: 65>
        position >= readLimit
                ifTrue: [^nil]
                ifFalse: [^collection at: (position _ position + 1)]! !

!InternalStream methodsFor: 'reading' stamp: 'ar 5/17/2008 07:34'!
next: anInteger
        "Answer the next anInteger elements of my collection.  overriden for efficiency"
        | ans endPosition |
        readLimit := readLimit max: position.
        endPosition := position + anInteger  min:  readLimit.
        ans := collection copyFrom: position+1 to: endPosition.
        position := endPosition.
        ^ans
! !

!InternalStream methodsFor: 'reading' stamp: 'ar 5/17/2008 07:32'!
next: n into: aCollection startingAt: startIndex
        "Read n objects into the given collection.
        Return aCollection or a partial copy if less than
        n elements have been read."
        | max |
        max := (readLimit - position) min: n.
        aCollection
                replaceFrom: startIndex
                to: startIndex+max-1
                with: collection
                startingAt: position+1.
        position := position + max.
        max = n
                ifTrue:[^aCollection]
                ifFalse:[^aCollection copyFrom: 1 to: startIndex+max-1]! !

!InternalStream methodsFor: 'reading' stamp: 'ar 5/17/2008 07:32'!
upTo: anObject
        "fast version using indexOf:"
        | start end |

        start := position+1.
        end := collection indexOf: anObject startingAt: start ifAbsent: [ 0 ].

        "not present--return rest of the collection"
        end = 0 ifTrue: [ ^self upToEnd ].

        "skip to the end and return the data passed over"
        position := end.
        ^collection copyFrom: start to: (end-1)! !

!InternalStream methodsFor: 'reading' stamp: 'ar 5/17/2008 07:33'!
upToEnd
        | start |
        start := position+1.
        position := collection size.
        ^collection copyFrom: start to: position! !


!InternalStream methodsFor: 'writing' stamp: 'ar 5/17/2008 08:50'!
next: anInteger putAll: aCollection startingAt: startIndex
        "Store the next anInteger elements from the given collection."
        | newEnd numPut |
        collection class == aCollection class ifFalse:
                [^ super next: anInteger putAll: aCollection startingAt: startIndex ].

        numPut := anInteger min: (aCollection size - startIndex + 1).
        newEnd := position + numPut.
        newEnd > self writeLimit ifTrue:
                [^ super next: anInteger putAll: aCollection startingAt: startIndex "Trigger normal pastEndPut: logic"].

        collection replaceFrom: position+1 to: newEnd with: aCollection startingAt: startIndex.
        position := newEnd.
! !

!InternalStream methodsFor: 'writing' stamp: 'ar 5/17/2008 08:46'!
nextPut: anObject
        "Primitive. Insert the argument at the next position in the Stream
        represented by the receiver. Fail if the collection of this stream is not an
        Array or a String. Fail if the stream is positioned at its end, or if the
        position is out of bounds in the collection. Fail if the argument is not
        of the right type for the collection. Optional. See Object documentation
        whatIsAPrimitive."

        <primitive: 66>
        ((collection class == ByteString) and: [
                anObject isCharacter and:[anObject isOctetCharacter not]]) ifTrue: [
                        collection _ (WideString from: collection).
                        ^self nextPut: anObject.
        ].
        position >= self writeLimit
                ifTrue: [^ self pastEndPut: anObject]
                ifFalse:
                        [position _ position + 1.
                        ^collection at: position put: anObject]! !

!InternalStream methodsFor: 'writing' stamp: 'ar 5/17/2008 08:46'!
nextPutAll: aCollection

        | newEnd |
        collection class == aCollection class ifFalse:
                [^ super nextPutAll: aCollection ].

        newEnd := position + aCollection size.
        newEnd > self writeLimit ifTrue:
                [self growTo: newEnd + 10].

        collection replaceFrom: position+1 to: newEnd  with: aCollection startingAt: 1.
        position := newEnd.! !


!InternalStream methodsFor: 'positioning' stamp: 'ar 5/17/2008 07:40'!
position: anInteger
        "Refer to the comment in PositionableStream|position:."
        readLimit := readLimit max: position.
        super position: anInteger! !

!InternalStream methodsFor: 'positioning' stamp: 'ar 5/17/2008 07:40'!
reset
        "Refer to the comment in PositionableStream|reset."
        readLimit := readLimit max: position.
        position := 0.! !

!InternalStream methodsFor: 'positioning' stamp: 'ar 5/17/2008 07:41'!
resetToStart
        readLimit := position := 0.! !

!InternalStream methodsFor: 'positioning' stamp: 'ar 5/17/2008 07:41'!
setToEnd
        "Refer to the comment in PositionableStream|setToEnd."

        readLimit := readLimit max: position.
        super setToEnd.! !


!InternalStream methodsFor: 'private' stamp: 'ar 5/17/2008 08:45'!
growTo: anInteger

   " anInteger is the required minimal new size of the collection "
        | oldSize grownCollection newSize |
        oldSize := collection size.
     newSize := anInteger + (oldSize // 4 max: 20).
        grownCollection := collection class new: newSize.
        collection := grownCollection replaceFrom: 1 to: oldSize with: collection startingAt: 1.
! !

!InternalStream methodsFor: 'private' stamp: 'ar 5/17/2008 08:50'!
pastEndPut: anObject
        "Grow the collection by creating a new bigger collection and then
        copy over the contents from the old one. We grow by doubling the size
        but the growth is kept between 20 and 1000000.
        Finally we put <anObject> at the current write position."

        | oldSize grownCollection |
        oldSize := collection size.
        grownCollection := collection class new: oldSize + ((oldSize max: 20) min: 1000000).
        collection := grownCollection replaceFrom: 1 to: oldSize with: collection startingAt: 1.
        collection at: (position := position + 1) put: anObject.
        "return the argument - added by kwl"
        ^ anObject! !

!InternalStream methodsFor: 'private' stamp: 'ar 5/17/2008 08:46'!
with: aCollection

        super on: aCollection.
        position := readLimit := aCollection size! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

InternalStream class
        instanceVariableNames: ''!

!InternalStream class methodsFor: 'instance creation' stamp: 'ar 5/17/2008 07:44'!
on: aCollection from: firstIndex to: lastIndex
        "Answer an instance of me on a copy of the argument, aCollection,
        determined by the indices firstIndex and lastIndex. Position the instance
        at the beginning of the collection."

        ^self basicNew
                on: aCollection
                from: firstIndex
                to: lastIndex! !

!InternalStream class methodsFor: 'instance creation' stamp: 'ar 5/17/2008 07:44'!
with: aCollection
        "Answer an instance of me on the argument, aCollection, positioned to
        store objects at the end of aCollection."

        ^self basicNew with: aCollection! !

!InternalStream class methodsFor: 'instance creation' stamp: 'ar 5/17/2008 07:44'!
with: aCollection from: firstIndex to: lastIndex
        "Answer an instance of me on the subcollection of the argument,
        aCollection, determined by the indices firstIndex and lastIndex. Position
        the instance to store at the end of the subcollection."

        ^self basicNew with: (aCollection copyFrom: firstIndex to: lastIndex)! !



Re: [squeak-dev] Re: A criticism of the Nile paper

by Avi Bryant-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, May 17, 2008 at 9:48 AM, Colin Putney <cputney@...> wrote:

Heh - I've long had nearly the opposite question: Why was support for read-write streams ever needed? I can't recall *ever* using it in my own code, nor encountering it in anyone else's.

What about files?

Avi



Re: [squeak-dev] Re: A criticism of the Nile paper

by Colin Putney :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 17-May-08, at 1:36 PM, Avi Bryant wrote:

On Sat, May 17, 2008 at 9:48 AM, Colin Putney <cputney@...> wrote:

Heh - I've long had nearly the opposite question: Why was support for read-write streams ever needed? I can't recall *ever* using it in my own code, nor encountering it in anyone else's.

What about files?

Good point. A lot of files are read-only or write-only, but not always. MC2's file repository both reads and writes on the same file stream. So I guess I have encountered it in someone else's code. :-)

Still, I do think separate streams for reading and writing to the same file would be fine as an API.

Colin




Re: [squeak-dev] Re: A criticism of the Nile paper

by Igor Stasenko :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

2008/5/18 Colin Putney <cputney@...>:

>
> On 17-May-08, at 1:36 PM, Avi Bryant wrote:
>
> On Sat, May 17, 2008 at 9:48 AM, Colin Putney <cputney@...> wrote:
>>
>> Heh - I've long had nearly the opposite question: Why was support for
>> read-write streams ever needed? I can't recall *ever* using it in my own
>> code, nor encountering it in anyone else's.
>
> What about files?
>
> Good point. A lot of files are read-only or write-only, but not always.
> MC2's file repository both reads and writes on the same file stream. So I
> guess I have encountered it in someone else's code. :-)
> Still, I do think separate streams for reading and writing to the same file
> would be fine as an API.
> Colin
>

Want to second that. In most cases read and write operations (even
operating with same device) serving different purposes, and really can
be used apart without much increase in code complexity.

Unless you using another trait - a positionable stream, the write and
read streams can be easily decoupled.


--
Best regards,
Igor Stasenko AKA sig.


Re: [squeak-dev] Re: A criticism of the Nile paper (was Re: My view on Traits)

by Damien Cassou-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thank you for your analyses. I'll have a close look as soon as
possible and will let you know.

On Sat, May 17, 2008 at 10:32 PM, Andreas Raab <andreas.raab@...> wrote:

> Damien Cassou wrote:
>>
>> I'm sorry. I haven't updated the universe package for some time.
>> Please use SqueakSource and load Nile-All. This package depends on
>> other required package and contains NSMetrics.
>
> Okay, after loading this I understand better where the numbers come from.
> First, a couple of comments on NSMetrics:
> #methodsInClassAndMetaclass:methodListBlock: does a union of methods in
> class and metaclass which looks a little questionable to me. I don't think
> it matters here but it seems odd to count a method in class and metaclass
> only once. The #numberOfReimplementedMethodsForClasses: also has two
> problems in such that it does only look at methods overridden in the direct
> superclass (so it doesn't find methods implemented in Stream and overridden
> in ReadStream but not in PositionableStream) and that it excludes the
> required selectors of traits but not those of superclasses (i.e., self
> subclassResponsibility) which it should discount as well (see note below on
> the metrics that are affected by it).
>
> That said, we can now devise a comparison which is more appropriate for a
> Nile vs. Squeak comparison. I've attached a simple class InternalStream
> which as a subclass of PositionableStream implements the same folding of
> ReadStream, WriteStream, and ReadWriteStream. I believe it to be a fully
> functioning equivalent to NSCollectionStream. If we run the design metrics
> using InternalStream instead of the three other classes we end up with
> metrics that look like this (slightly reformatted from the TeX output):
>
>                                 Squeak  Nile (Squeak-Nile)/Squeak
> Number of Classes And Traits        3      6          -100%
> Number of Classes                   3      1            66%
> Number of Methods                  39     33            15% [*1]
> Number of Bytes                  1328   1078            18%
> Number of Cancelled Methods         0      0             0%
> Number of Reimplemented Methods    10      3            70% [*1]
> Number of Methods Impl. Too High    0      0             0%
>
> [*1] This includes 2 subclassResponsibilities in Squeak which should be
> discounted as pointed out above.
>
> The main differences are in the number of entities as well as in the number
> of methods (overrides). Looking at it in detail it turns out that the larger
> number of entities comes purely