FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Library Chaos
Goto page Previous  1, 2
 
Post new topic   Reply to topic     Forum Index -> Ares
View previous topic :: View next topic  
Author Message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Fri Jan 06, 2006 7:09 pm    Post subject: Re: Perfect Library. Reply with quote

thedracle wrote:
Normal File I/O, Socket I/O can be implemented pretty simply, i.e:

Code:

File myFile = new File("filename.dat", "rw+");
TCPSocket mySocket = new TCPSocket("bob.nowhere.com", 8020);
bit processLine(char[] nextLine)
{
   char[][] matches;
   if((matches = nextLine.matches(someRegExp) != null)
   {
      // Do something.
   }
}
myFile.eachLine(&processLine);
mySocket.eachLine(&processLine);


Basically the File object, and the Socket object, both implement an underlying IO interface that has the eachLine, eachByte, etc... functions.

I find that it can be more useful to expose a common interface from files/sockets/console etc, and then hook an appropriate tokenizer to it. This permits extensibility without changing existing modules, manages code-bloat, and handles unicode quite nicely.

Code:
auto line = new LineStream (new FileConduit ("myFile"));
while (line.next)
         Println (line.get);

Tokenizers support foreach, and expose an equivalent bool visit(bool delegate(T[])) method
Back to top
View user's profile Send private message
thedracle



Joined: 25 Dec 2005
Posts: 11

PostPosted: Sat Jan 07, 2006 7:02 pm    Post subject: Some thoughts on delegates Vs. Streams & Wrappers Reply with quote

It really isn't much different to say:

Code:

File mFile = new File("myFile", "rw+");
void mDelegate(char[] line)
{
   Println(line);
}
mFile.eachLine(&mDelegate);


instead of the Java way:
Code:

auto line = new LineStream (new FileConduit ("myFile"));
while (line.next)
         Println (line.get);

Keeping in mind the ugly caveats of this method as well:
Code:

auto x = new LineStream(ArrayConduit(xArray));
auto j = new LineStream(ArrayConduit(jArray));
while(x.next)
   while(j.next)
      doSomething(x.get, j.get);
/* Wait, I quickly run out of x's because I didn't pack it into a local variable.*/


(The interface File meets exposes the various types of basic reads to it, rather than having to create a new object for every single type of iterator. Does LineStream really constitute an individual object--- or a type of iteration can can be performed on a generic stream?)

Except the closure code hides primitive iterators, being that while(line.next) is in itself a trick, since null and 0 happen to both evaluate to false. Suppose you wanted a backwards iterator, would you do line.previous? Or would line.next be convoluted to mean the previous element? Already you're getting into the details of the specific implementation of the iterator.

The details of iteration should belong to the service provider class, and the details of such iteration should be hidden from the client.

For a reverse iterator, you could do: myArray.reverseEach(&mDelegate); using closures.

Using wrapper streams, you decouple the iteration from the service class, having it provide some primitive methods underneath that it uses to derive lines from, or whatever type it will provide back to the user. You have to provide a wrapper stream for every single type of iteration that can be performed on that particular item, but you also need to build a hierarchy for niche types of iteration that don't apply generally.

For instance, say you have a Binary Tree. It will share basic operations with other 'Conduit's, but suppose you wanted to do depth-first iteration or breadth-first iteration. This would only make sense for a small subset of types, and not all "Conduit" objects you'll be dealing with. Therefor, you'll pretty quickly be building a rather large hierarchy, using the class system to prevent users from misusing your generic streams. Or you're internal to the BreadthFirstStream class using reflection to make sure this type of iteration makes sense for this particular conduit--- or you're placing methods for supporting these operations in the Conduit object, and having implementers that it doesn't make sense for display some error message during runtime.

Loop abstraction using the higher-order style is heavily documented in functional programming languages, Smalltalk, Ruby, and lots of other non-C based languages. There's a reason why the purely object oriented, template language for design-patterns, Smalltalk, decided to adopt this style for use with iteration. I would avoid using Java-style streams, and wrappers, overall.

Gotta take off now, but I look forward to looking over this further.

-Jason Thomas.
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Sun Jan 08, 2006 2:29 pm    Post subject: Re: Some thoughts on delegates Vs. Streams & Wrappers Reply with quote

thedracle wrote:
It really isn't much different to say:

Code:

File mFile = new File("myFile", "rw+");
void mDelegate(char[] line)
{
   Println(line);
}
mFile.eachLine(&mDelegate);


instead of the Java way:
Code:

auto line = new LineStream (new FileConduit ("myFile"));
while (line.next)
         Println (line.get);

Actually there is quite a significant difference. The former potentially has to maintain state across callbacks, and the functionality provided (for each type of visitor-pattern) would have to be, by definition, built into the base class for File and others. The latter (decoupled) style, whilst it certainly has limitations, does not impose such constraints or maintenance concerns; although (as noted) it can happily expose the callback/delegate approach too: lines.visit(&delegate);

thedracle wrote:
Keeping in mind the ugly caveats of this method as well:
Code:

auto x = new LineStream(ArrayConduit(xArray));
auto j = new LineStream(ArrayConduit(jArray));
while(x.next)
   while(j.next)
      doSomething(x.get, j.get);
/* Wait, I quickly run out of x's because I didn't pack it into a local variable.*/

(The interface File meets exposes the various types of basic reads to it, rather than having to create a new object for every single type of iterator. Does LineStream really constitute an individual object--- or a type of iteration can can be performed on a generic stream?)

Except the closure code hides primitive iterators, being that while(line.next) is in itself a trick, since null and 0 happen to both evaluate to false. Suppose you wanted a backwards iterator, would you do line.previous? Or would line.next be convoluted to mean the previous element? Already you're getting into the details of the specific implementation of the iterator.

As noted, one could just as easily use a callback approach with stream iterators. Perhaps you'd like to provide an equivalent example for the above, using generic callbacks? One can quickly end up with a lot of transient state to maintain?

One should also keep in mind the several distinctions between a true streaming model and an pseudo streaming model; one distinction is that the former does not have all content available to traverse, whilst the latter typically does. Thus to iterate backwards over a, say, SocketConduit would require an initial operation to cache the result locally. That actually turn the original stream into something else ~ the two models are not really comparable in their original state.


thedracle wrote:
The details of iteration should belong to the service provider class, and the details of such iteration should be hidden from the client.

For a reverse iterator, you could do: myArray.reverseEach(&mDelegate); using closures.

Using wrapper streams, you decouple the iteration from the service class, having it provide some primitive methods underneath that it uses to derive lines from, or whatever type it will provide back to the user. You have to provide a wrapper stream for every single type of iteration that can be performed on that particular item, but you also need to build a hierarchy for niche types of iteration that don't apply generally.

Yes and no. Unfortunately there are many tradeoffs here, just as there is with all other aspects of library development. On the one hand there's a valid and long-standing desire to "seperate the things that change from those that stay the same" ~ meaning it's usually a good idea to provide for extensibility outside of the library provisions (thus, we have independent, decoupled, stream visitors). On the other hand, there's a desire to make a library as symmetrical as possible ~ a wish to be able to use any one thing with any other. In the middle are concerns regarding overhead and maintenence, amongst others.

The decoupling you note is there for good reason. If one were to provide a, say, Regex visitor for a File, then every user of the File would wind up with the Regex code bound to their application whether it were used or not. Rinse and repeat with all other tightly-coupled functionality. And let's not forget about all the char/wchar/dchar variations either ... This is a major difference between statically and dynamically linked languages. D belongs in the former camp, where tightly-coupled libraries can quickly fall out of favour. More tradeoffs.

thedracle wrote:
For instance, say you have a Binary Tree. It will share basic operations with other 'Conduit's, but suppose you wanted to do depth-first iteration or breadth-first iteration. This would only make sense for a small subset of types, and not all "Conduit" objects you'll be dealing with. Therefor, you'll pretty quickly be building a rather large hierarchy, using the class system to prevent users from misusing your generic streams. Or you're internal to the BreadthFirstStream class using reflection to make sure this type of iteration makes sense for this particular conduit--- or you're placing methods for supporting these operations in the Conduit object, and having implementers that it doesn't make sense for display some error message during runtime.


A stream is quite a different animal from a binary tree. The former is typically linear access only, whereas the latter is effectively random access. If one turned the stream into the equivalent of a local file, then it could be visited in a manner comparable (conceptually) to the tree.

thedracle wrote:
Loop abstraction using the higher-order style is heavily documented in functional programming languages, Smalltalk, Ruby, and lots of other non-C based languages. There's a reason why the purely object oriented, template language for design-patterns, Smalltalk, decided to adopt this style for use with iteration. I would avoid using Java-style streams, and wrappers, overall

I'm personally rather fond of the higher-order style you note. But they too have their limitations and issues (which you haven't mentioned). Neither approach is free from negative association so, again, it's all about the tradeoffs one is content to live with, and the type of language under consideration. Wouldn't you agree?

Another approach would be to support the binding of a visitor-instance to some of the various primary classes (such as File, Socket, Console, etc), and provide a common means of invocation. Thus one might have:
Code:
auto file = new FileConduit ("myfile");
file.bind (new RegexTokenizer ("some pattern");
file.iterate (&delegate);

While certainly not ideal, it somewhat reflects the kind of thing you're suggesting, minus the statically-linked concerns? Given a choice between the two, I think I'd prefer this approach instead (and I suspect you would too):

Code:
auto patterns = new RegexStream (new FileConduit("myFile"), "some pattern");
patterns.visit (&delegate);


Having said all that, it would certainly be feasible to build a limited set of functionality in the delegation manner described ~ the trick would be to balance functionality vs code-bloat. One way to do that (with respect to IO) would be to split the library along a strongly distinguishing characteristic. Thus, you'd have two smaller areas to resolve instead of one big one. I'm currently investigating this approach Smile
Back to top
View user's profile Send private message
thedracle



Joined: 25 Dec 2005
Posts: 11

PostPosted: Mon Jan 09, 2006 6:56 pm    Post subject: Interesting. Reply with quote

Kris:
Quote:

Actually there is quite a significant difference. The former potentially has to maintain state across callbacks, and the functionality provided (for each type of visitor-pattern) would have to be, by definition, built into the base class for File and others. The latter (decoupled) style, whilst it certainly has limitations, does not impose such constraints or maintenance concerns; although (as noted) it can happily expose the callback/delegate approach too: lines.visit(&delegate);


I didn't mean there isn't a functional difference between the two, the iterator is likely going to be faster for instance, I simply meant that from a programmer's standpoint--- you're essentially performing the same conceptual operation. From the programmer's perspective, however, you really don't have to care about exactly how the stream is being iterated over, those details are entirely hidden. You're stripped down to precisely to the minimum of what you need to know about that entire operation.

About having to maintain state across callbacks, I'm not exactly certain what you mean--- do you mean the overhead of maintaining the state of the stack above the callback?

Or maybe the service maintaining an internal state of the stream?

It should internally save some hidden state of the data-stream in the background (Which is arguably good):
i.e:
Code:

bit lineHandler(char[] nextLine)
{
   bit byteHandler(byte nextByte)
   {
      // Do something with the bytes.
      return doSomethingWithAByte(nextByte);
   }
   if(someCondition)
      mFile.eachByte(byteHandler);
   else doSomethingWithALine(nextLine);
}
mFile.eachLine(&handleLine);


Should operate apropriately, the data in the file is consumed by both iterators, and they each continue from the respective position where the other left off.

I'm probably totally missing your point. Could you provide a little example to demonstrate what you meant?

kris:
Quote:

One should also keep in mind the several distinctions between a true streaming model and an pseudo streaming model; one distinction is that the former does not have all content available to traverse, whilst the latter typically does. Thus to iterate backwards over a, say, SocketConduit would require an initial operation to cache the result locally. That actually turn the original stream into something else ~ the two models are not really comparable in their original state.


Yes, this was precisely my point. Using callbacks seems to allow for this type of abstraction, while Iterators seem to presume more about the internal state of what they're operating on. I was simply pointing out that a Conduit would have to represent a set of objects on which all of the provided visitors would make sense operating upon. The provided Visitor interface would account for all possible visitor types, and the implementing Conduit would have to simply provide a runtime error for a type of Visitor that didn't make sense for that particular stream. or perhaps define a new kind of Conduit and Visitor interface? Using callbacks, you'd have a base type that would provide forward iteration--- since Sockets, and Files, despite their difference, share this base functionality. You could provide further interfaces on top of that which provide more specific functionality.

kris:
Quote:

The decoupling you note is there for good reason. If one were to provide a, say, Regex visitor for a File, then every user of the File would wind up with the Regex code bound to their application whether it were used or not. Rinse and repeat with all other tightly-coupled functionality. And let's not forget about all the char/wchar/dchar variations either ... This is a major difference between statically and dynamically linked languages. D belongs in the former camp, where tightly-coupled libraries can quickly fall out of favour. More tradeoffs.


This is a good point, since the service references through its interface all of the possible iterator types beneath it--- it would require an implementation for those to be built in despite their being used or not. This is a reality of D I didn't really consider to begin with. For embedded development, I can see this type of bloat being unacceptable. Using visitors obviously allows for adding a plethora of differing types of iterators--- thus a more dynamic nature. It also allows for the code for each of these different types of iterators to exist in completely separate modules, blind to one another.

Quote:

A stream is quite a different animal from a binary tree. The former is typically linear access only, whereas the latter is effectively random access. If one turned the stream into the equivalent of a local file, then it could be visited in a manner comparable (conceptually) to the tree.


Yes, this was my point, a Visitor for this type of iteration wouldn't make sense for all conduits, but it's pretty simple to implement unique iterations to a binary tree using callbacks--- while staying consistent with the I/O model you've chosen, and not stepping on any toes elsewhere.

Quote:

I'm personally rather fond of the higher-order style you note. But they too have their limitations and issues (which you haven't mentioned). Neither approach is free from negative association so, again, it's all about the tradeoffs one is content to live with, and the type of language under consideration. Wouldn't you agree?


I agree completely, everything has its limitations, I'm just interested in the relative merits of the two. I think, overall, higher-order-style is better, but you've brought up some interesting points on why this may not be the case in D.

I especially like your examples below:

Kris:
Quote:

Another approach would be to support the binding of a visitor-instance to some of the various primary classes (such as File, Socket, Console, etc), and provide a common means of invocation. Thus one might have:
Code:

auto file = new FileConduit ("myfile");
file.bind (new RegexTokenizer ("some pattern");
file.iterate (&delegate);

// Or

auto patterns = new RegexStream (new FileConduit("myFile"), "some pattern");
patterns.visit (&delegate);



It seems to hide the details of the iteration quite well. But it still has all of the hierarchical problems. I think it's a good compromise though. I'd like to see the iterator expose no other way to get at the data than through a delegate. This is actually pretty damn cool--- I'll have to think about it some more.

Maybe we can list the pro's and con's of both approaches, and see what this new approach solves. The thing is, the problems with hierarchy can be probably designed out of existence, where as the problems with code bloat are inherent to my method, and simply can not.

-Jason Thomas.
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Mon Jan 09, 2006 7:20 pm    Post subject: Re: Interesting. Reply with quote

thedracle wrote:
It seems to hide the details of the iteration quite well. But it still has all of the hierarchical problems. I think it's a good compromise though.

True, true, and true. All too true Smile
Back to top
View user's profile Send private message
thedracle



Joined: 25 Dec 2005
Posts: 11

PostPosted: Mon Jan 09, 2006 9:24 pm    Post subject: Reply with quote

Code:

auto patterns = new RegexStream (new FileConduit("myFile"), "some pattern");
patterns.visit (&delegate);


One reason why this is better than using bind is because bind limits the Conduit to one type of I/O.

You could, for instance, do something like:

Code:

// Iterator instead of stream?
LineIterator mIterator = new LineIterator(new FileConduit("myFile"));
bit lineConsumer(char[] nextLine)
{
   bit byteConsumer(char[] nextByte)
   {
      return doSomethingWithByte(nextByte);
   }
   ByteIterator bIterator = new ByteIterator(new FileConduit("myFile"));
   if(doSomethingWithLine(nextLine))
      bIterator.each(&byteConsumer);
}
// Each instead of visit?
mIterator.each(&lineConsumer);


It's more compact, and you can attach more than one type of iterator to it at a time, and hopefully it will handle everything okay. With bind you'll have to attach one, and make sure to attach the other, etc...

It also seems like a LineIterator doesn't store any real state data--- a RegExp iterator doesn't either, except it's technically binded to some particular RegExp object. Maybe ByteIterator can use singleton, i.e ByteIterator mIt = ByteIterator.getIterator(); And RegExpIterator can use a singleton that keeps a pool of already existing RegExpIterators indexed by the RegExps they use, and return the identical one?

I thought of having a Factory to produce these--- but it would end up becoming segmented anyways to make sure that we avoid code-bloat yet again.

-Jason Thomas.
Back to top
View user's profile Send private message
sean



Joined: 24 Jun 2004
Posts: 609
Location: Bay Area, CA

PostPosted: Mon Jan 09, 2006 9:30 pm    Post subject: Reply with quote

thedracle wrote:
It's more compact, and you can attach more than one type of iterator to it at a time, and hopefully it will handle everything okay. With bind you'll have to attach one, and make sure to attach the other, etc...

...and if the iterator needs to retain state information--LineIterator might need to buffer data up to line end, for example--you're sunk. It also makes this more of a pure extension, as it requires basically no changes to the Conduit code.
Back to top
View user's profile Send private message
thedracle



Joined: 25 Dec 2005
Posts: 11

PostPosted: Mon Jan 09, 2006 10:10 pm    Post subject: Yeah--- But will it? Reply with quote

We should try to implement buffering beneath it, especially due to my example above where the actual relative location between Iterators is important--- it would be nice if the Iterator itself didn't have to deal with position information within the file. This may not be practical though, I'll hae to think about it some more.

-Jason Thomas.
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Fri Jan 13, 2006 7:05 am    Post subject: Re: Yeah--- But will it? Reply with quote

thedracle wrote:
We should try to implement buffering beneath it, especially due to my example above where the actual relative location between Iterators is important--- it would be nice if the Iterator itself didn't have to deal with position information within the file. This may not be practical though, I'll hae to think about it some more.

If you haven't done so, you might consider taking a look at Mango? All the things I've mentioned here are based on experience with that library. There's been a recent refactoring of the original Tokenizer framework (like the iterators above, but for text only), that removed some of the original ugliness and migrated the functionality to the mango.text package instead.

Mango tokenizers/text-iterators have always been based upon a Buffer, which acts as a switch-point between Sockets, Files, MemoryMapped files, in-memory Strings, Console, etc. The mango.io package is based upon these Buffers also. It features a set of Reader and Writer facades, with pluggable unicode translation.

The upshot is that multiple Readers and Iterators can bind to a single instance of a Buffer, and each will stay in lockstep. You can also map Readers and Iterators onto the result of an 'iteration'. For example, one can easily map the result of a 'line' token into a Reader or another Iterator for localized-processing. One might think of the Buffer as indirection for input facades.

That aside; the iterators we've discussed are for reading only. What happens when writing? Currently, mango.io uses the Writer facade alone for this purpose. I haven't found much use for an iterator pattern during a write operation (other than for traversing a data-structure).
Back to top
View user's profile Send private message
sean



Joined: 24 Jun 2004
Posts: 609
Location: Bay Area, CA

PostPosted: Fri Jan 13, 2006 8:17 am    Post subject: Re: Yeah--- But will it? Reply with quote

kris wrote:
That aside; the iterators we've discussed are for reading only. What happens when writing? Currently, mango.io uses the Writer facade alone for this purpose. I haven't found much use for an iterator pattern during a write operation (other than for traversing a data-structure).

It's rare, but I do occasionally use ostream_iterator in C++ (usually for traversing a data structure, as you've mentioned):
Code:
typedef ... MyCont;
MyCont myCont;

std::copy( myCont.begin(), myCont.end(), std::ostream_iterator<MyCont::value_type>( std::cout, "\n" ) );

Pretty ugly, but no less verbose than a for loop would have been.
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Fri Jan 13, 2006 8:38 am    Post subject: Re: Yeah--- But will it? Reply with quote

sean wrote:
kris wrote:
That aside; the iterators we've discussed are for reading only. What happens when writing? Currently, mango.io uses the Writer facade alone for this purpose. I haven't found much use for an iterator pattern during a write operation (other than for traversing a data-structure).

It's rare, but I do occasionally use ostream_iterator in C++ (usually for traversing a data structure, as you've mentioned):
Code:
typedef ... MyCont;
MyCont myCont;

std::copy( myCont.begin(), myCont.end(), std::ostream_iterator<MyCont::value_type>( std::cout, "\n" ) );

Pretty ugly, but no less verbose than a for loop would have been.


This is why mango.io has the IWritable interface (and IReadable) ~ so you can make the data structure itself compatable with the IO layer. While I'm not entirely clear on the above, I think mango.io could handle it in the following manner?

Code:
write (myCont);

  or perhaps

write (myCont.subset);
Back to top
View user's profile Send private message
sean



Joined: 24 Jun 2004
Posts: 609
Location: Bay Area, CA

PostPosted: Fri Jan 13, 2006 9:22 am    Post subject: Reply with quote

std::copy is implemented roughly like so:
Code:
template copy(SrcIter, DstIter) {
    void copy( SrcIter beg, SrcIter end, DstIter out ) {
        while( beg != end ) {
            out++ = beg++;
        }
    }
}

So the example just iterates across the range [beg..end) and (in this case) prints the objects one at a time. For the common case, that's equivalent to your "write" examples. The cool thing about iterators however is that they aren't required to be objects--pointers are valid iterators. So this is legal too:
Code:
char buf[1024];
char* beg = &buf[0];
char* end = &buf[1024];

std::copy( beg, end, std::ostream_iterator<char>( std::cout ) );

This will print the contents of buf to the screen.

Slicing/selection does address this to a large degree in D, though foreach doesn't yield an obvious generic equivalent to std::copy:
Code:
template copy(T : T[], U : U[]) {
    void copy( T[] src, U[] dst ) {
        size_t pos = 0;
        foreach( T val; src ) {
            dst[pos] = val;
        }
    }
}

The above function works for array slices, but what about objects that simply implement opApply? And what if the destination isn't an array either? It seems like a series of template specializations would be required to address every case, and the result still might not be as flexible as the C++ verison. I'll admit that this is my major concern about using foreach as the D 'theme'. While it supports ad-hoc coding much better than the occasional need for one-off objects and sometimes awkward template composition that can crop up in C++, it doesn't seem to address certain common use cases nearly as well.

That said... this is largely a matter of mindset, as D isn't C++ Smile Also, Matthew was doing some promising work here with selection and ranges. Perhaps I'll revisit DTL and see if anything jumps out at me--it's been so long that I don't remember the semantics he'd come up with. And finally, I really need to spend some time with Mango to get a better feel for how it handles all this. I'm about done with the proposal/review work I've been doing for the moment, so perhaps I can do that in the next few (business) days (I never seem to find much "free time" during the weekend Wink).
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Fri Jan 13, 2006 9:39 am    Post subject: Reply with quote

sean wrote:
I'll admit that this is my major concern about using foreach as the D 'theme'

I agree.

Foreach is really handy to have as a backup option, since it has limited capabilites. However, I've seen foreach used with selections also (like you mentioned). I think foreach and iterators are much closer cousins than they might seem at first blush Smile

If one designs with iterators in mind, the result can often be used with both the classic iterator and the foreach approaches. One might imagine a little indirection within the foreach preamble?
Back to top
View user's profile Send private message
thedracle



Joined: 25 Dec 2005
Posts: 11

PostPosted: Mon Jan 16, 2006 10:02 pm    Post subject: Hm. Reply with quote

Kris, I've looked at Mango a bit. Basing things on buffers in the background seems like a pretty good idea. About the abilities of STL to deal with pointers and iterators the same--- this may be advantageous in certain ways, but as we've pointed out, from a design perspective it's disasterous. For one, readability and clarity are of extreem importance. The same thing could be accomplished using a wrapper of some kind around a primitive array, and maintain readability. I'd like to explore comparative flexability of these different methods. I have no doubt that C++ can be a great deal more flexable in a lot of ways--- but this isn't always a desireable thing when it comes with such high penalties.

-Jason Thomas.
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Mon Jan 16, 2006 11:06 pm    Post subject: Re: Hm. Reply with quote

thedracle wrote:
Kris, I've looked at Mango a bit. Basing things on buffers in the background seems like a pretty good idea. About the abilities of STL to deal with pointers and iterators the same--- this may be advantageous in certain ways, but as we've pointed out, from a design perspective it's disasterous. For one, readability and clarity are of extreem importance. The same thing could be accomplished using a wrapper of some kind around a primitive array, and maintain readability. I'd like to explore comparative flexability of these different methods. I have no doubt that C++ can be a great deal more flexable in a lot of ways--- but this isn't always a desireable thing when it comes with such high penalties.

-Jason Thomas.

I'll certainly be interested to see what you devise Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Ares All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group