digitalmars.D - Non-pipeline component programming
- =?UTF-8?B?Ikx1w61z?= Marques" (27/27) Feb 03 2014 I loved reading Walter's component programming article in Dr.
- Zoadian (6/35) Feb 04 2014 We're currently working on an Entity Component System for D (
- Francesco Cattoglio (16/19) Feb 04 2014 I've seen it too. I like it so far, because of the nice usage of
- Paul Freund (8/16) Feb 04 2014 We are currently working on the first "stable" version (and API).
- Francesco Cattoglio (14/20) Feb 04 2014 That's really good news! A friend of mine was trying to get an
- =?UTF-8?B?Ikx1w61z?= Marques" (15/20) Feb 05 2014 After carefully reading the material, I think that the Entity
- Mike Parker (19/25) Feb 05 2014 Conceptually, it's not related. The only similarity is the use of
- Meta (8/12) Feb 06 2014 That seems cool. I can only imagine the possibilities...
- Paul Freund (11/23) Feb 06 2014 You're example almost works. With the EntityComponentManager API
- Mike Parker (3/13) Feb 07 2014 Ah, so there's no data-orientation here. It's strictly entity-centric.
- Zoadian (24/44) Feb 07 2014 There will be a way to iterate directly over components.
- Francesco Cattoglio (3/14) Feb 07 2014 This looks nice and everything, but won't it slow down access
- Marco Leise (22/39) Feb 07 2014 Yeah, looks like a point is now spread over 3 cache lines.
- nikki (6/6) Sep 04 2014 I've written a coffeescript Entity Component System
- nikki (2/2) Sep 04 2014 http://t-machine.org/index.php/2014/03/08/data-structures-for-entity-sys...
- H. S. Teoh (52/75) Feb 12 2014 Sorry for this belated reply, I have been rather busy with other
- David Ledez (12/132) Sep 04 2014 Dear T,
- H. S. Teoh via Digitalmars-d (84/91) Sep 10 2014 Sorry for the very late reply; my internet connection was down for 2
- Chris (11/88) Sep 04 2014 I found myself using singelton classes more and more until I
- Paulo Pinto (24/68) Sep 04 2014 In Smalltalk and Eiffel, where everything is an object this tends
I loved reading Walter's component programming article in Dr. Dobb's [0] in late 2012. I had missed H. S. Teoh's mid 2013 article on calendar textual formatting using the component approach [1], but fortunately Ali brought it to my attention recently, and I also find it absolutely fascinating! I think what's most interesting with Teoh's article (and I think that was Ali's point when he mentioned the article to me) is that the calendar example is not as an obvious target for the component approach, or at least that the design and implementation is not as obvious for someone new to that approach. Now, while Teoh's example is much more complex than Walter's, both examples are for cases of pipelined problems (source -> filter1 -> filter2 -> sink). What I have been wondering during the last few days is how much this "component programming" approach could be applied to scenarios where you would normally have a jumble of objects. For instance, try to picture a game or simulation where spaceships fire at each other, pick up objects, communicate, and so on, or something like that. My instinct would be to code a solution which would be classified as typical OOP code. Would it be possible to come up with a solution that would be more in the spirit of "component programming"? Or are such solutions only practical/applicable for pipeline-like scenarios? -- [0] http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321 [1] http://wiki.dlang.org/User:Quickfur/Component_programming_with_ranges
Feb 03 2014
We're currently working on an Entity Component System for D ( https://github.com/Zoadian/nitro) Here some good explanations: http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/ http://www.richardlord.net/blog/what-is-an-entity-framework On Tuesday, 4 February 2014 at 04:12:49 UTC, Luís Marques wrote:I loved reading Walter's component programming article in Dr. Dobb's [0] in late 2012. I had missed H. S. Teoh's mid 2013 article on calendar textual formatting using the component approach [1], but fortunately Ali brought it to my attention recently, and I also find it absolutely fascinating! I think what's most interesting with Teoh's article (and I think that was Ali's point when he mentioned the article to me) is that the calendar example is not as an obvious target for the component approach, or at least that the design and implementation is not as obvious for someone new to that approach. Now, while Teoh's example is much more complex than Walter's, both examples are for cases of pipelined problems (source -> filter1 -> filter2 -> sink). What I have been wondering during the last few days is how much this "component programming" approach could be applied to scenarios where you would normally have a jumble of objects. For instance, try to picture a game or simulation where spaceships fire at each other, pick up objects, communicate, and so on, or something like that. My instinct would be to code a solution which would be classified as typical OOP code. Would it be possible to come up with a solution that would be more in the spirit of "component programming"? Or are such solutions only practical/applicable for pipeline-like scenarios? -- [0] http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321 [1] http://wiki.dlang.org/User:Quickfur/Component_programming_with_ranges
Feb 04 2014
On Tuesday, 4 February 2014 at 09:49:39 UTC, Zoadian wrote:We're currently working on an Entity Component System for D ( https://github.com/Zoadian/nitro) Here some good explanations:I've seen it too. I like it so far, because of the nice usage of templates, but right now I didn't gave it a try due to zero docs. The questions asked by Luìs probably has more to do with "if I'm iterating one entity/component at a time, how can I access two components at one time for my computations?" The easy way is just using the cartesian product of your range with itself. http://dlang.org/phobos/std_algorithm.html#cartesianProduct This way you get a range of tuples, so you get pairs made of each entity with all the other ones, and you can process that pair with your next filter function. After that I'm not really sure about what one could do. Another approach could be: pass (a copy of your) RA range to a filter, and use that to compute the effects for each entity. Bang, every entity is now processed.
Feb 04 2014
On Tuesday, 4 February 2014 at 10:06:18 UTC, Francesco Cattoglio wrote:On Tuesday, 4 February 2014 at 09:49:39 UTC, Zoadian wrote:We are currently working on the first "stable" version (and API). The master branch is the last working state but our current development is in the finalize_basics (https://github.com/Zoadian/nitro/tree/finalize_basics) branch, including a work in progress documentation. It should be ready to use and documented in a few days.We're currently working on an Entity Component System for D ( https://github.com/Zoadian/nitro) Here some good explanations:I've seen it too. I like it so far, because of the nice usage of templates, but right now I didn't gave it a try due to zero docs.
Feb 04 2014
On Tuesday, 4 February 2014 at 10:24:57 UTC, Paul Freund wrote:We are currently working on the first "stable" version (and API). The master branch is the last working state but our current development is in the finalize_basics (https://github.com/Zoadian/nitro/tree/finalize_basics) branch, including a work in progress documentation. It should be ready to use and documented in a few days.That's really good news! A friend of mine was trying to get an entity system working with a etc.c.sqlite3 "backend", but right now he isn't that much satisfied by it. The main reason for having it on DB was having every component on a separate table, and because we plan on having LOTS of entities (~1 Million) (a DB should be able to handle that). Throw in the mix "free saving of state on file" and you can see why he made this choice. Taking a better look at it, your store every entity in a separate table, too! If performance will be good, I think we might switch to nitro for our project. Besides, I don't think that sqlite performance is that great for the amount of granularity we need. Pretty sure there are just too many casts going around. (3 bytes integers??? ARE YOU SERIOUS?)
Feb 04 2014
On Tuesday, 4 February 2014 at 09:49:39 UTC, Zoadian wrote:We're currently working on an Entity Component System for D ( https://github.com/Zoadian/nitro) Here some good explanations: http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/ http://www.richardlord.net/blog/what-is-an-entity-frameworkAfter carefully reading the material, I think that the Entity System / Entity Component System (ECS) framework is indeed a good design, and provides a good answer for the specific example I was considering (spaceships, etc.). Still, I wonder how related to the (pipelined) component approach described by Walter and Teoh this ECS approach really is. Perhaps more specifically, I wonder if the ECS approach also allows using a lot of the std.algorithms, like was done in the pipelined component approach, and in the calendar example in particular. Also, I'm a bit lost with the Nitro code and how to use it. (Tangentially, two things that I was wondering while reading about the ECS: how important would it be to have non-polymorphic reference types, and why are we paying for the object monitor field when that approach seems to be outdated, especially in D)
Feb 05 2014
On Wednesday, 5 February 2014 at 15:29:14 UTC, Luís Marques wrote:Still, I wonder how related to the (pipelined) component approach described by Walter and Teoh this ECS approach really is. Perhaps more specifically, I wonder if the ECS approach also allows using a lot of the std.algorithms, like was done in the pipelined component approach, and in the calendar example in particular.Conceptually, it's not related. The only similarity is the use of the word "component." An ECS is concerned with breaking traditional objects into disparate, composable parts. This can be combined with the concept of Data-Oriented Programming (DOP), to improve cache locality when iterating entities, by storing all components of the same type in a contiguous block of memory. Then rather than iterating an array of entities and calling a setFoo method, you can instead more efficiently iterate an array of Foos independent of each entity. The pipelined component concept is about chaining a set of operations to transform a dataset where the output of one transformation is the input to the next. Here, the "components" are not the data but the transformations, which can be swapped in and out, reordered, or added to and removed from the chain. A cursory look at Nitro suggests they are using an ECS with DOP. Given that they're providing ranges for iterating the data, it will fit into D's range-based component pipelines (std.algorithm and such).
Feb 05 2014
On Thursday, 6 February 2014 at 05:27:22 UTC, Mike Parker wrote:A cursory look at Nitro suggests they are using an ECS with DOP. Given that they're providing ranges for iterating the data, it will fit into D's range-based component pipelines (std.algorithm and such).That seems cool. I can only imagine the possibilities... auto shipComponents = components.filter!(a => a.hasComponent!SpaceShip); foreach (i, spaceship; taskPool.parallel(shipComponents)) { spaceship.name = format("Ship %i", i); }
Feb 06 2014
On Thursday, 6 February 2014 at 13:47:22 UTC, Meta wrote:On Thursday, 6 February 2014 at 05:27:22 UTC, Mike Parker wrote:You're example almost works. With the EntityComponentManager API it works like this: auto shipEntities = ecm.query!SpaceShip(); foreach (i, spaceship; taskPool.parallel(shipEntities)) { auto shipData = spaceship.getComponent!SpaceShip(); shipData.name = format("Ship %i", i); } Now that unittests are written, documentation is on its way and should be ready in a few days.A cursory look at Nitro suggests they are using an ECS with DOP. Given that they're providing ranges for iterating the data, it will fit into D's range-based component pipelines (std.algorithm and such).That seems cool. I can only imagine the possibilities... auto shipComponents = components.filter!(a => a.hasComponent!SpaceShip); foreach (i, spaceship; taskPool.parallel(shipComponents)) { spaceship.name = format("Ship %i", i); }
Feb 06 2014
On 2/7/2014 12:14 AM, Paul Freund wrote:You're example almost works. With the EntityComponentManager API it works like this: auto shipEntities = ecm.query!SpaceShip(); foreach (i, spaceship; taskPool.parallel(shipEntities)) { auto shipData = spaceship.getComponent!SpaceShip(); shipData.name = format("Ship %i", i); } Now that unittests are written, documentation is on its way and should be ready in a few days.Ah, so there's no data-orientation here. It's strictly entity-centric. Or do you have a way to iterate components independently of entities?
Feb 07 2014
On Friday, 7 February 2014 at 08:09:10 UTC, Mike Parker wrote:On 2/7/2014 12:14 AM, Paul Freund wrote:There will be a way to iterate directly over components. Component fields will automatically be split into an structure of arrays. So let's assume we have: struct Point {int x; int y; int z; } Component struct Translation { int a; Point b; Point c; } Nitro will store Translation like this, so it is even possible to iterate over parts of components: Entity[] int[] for a int[] for b.x int[] for b.y int[] for b.z int[] for c.x int[] for c.y int[] for c.z Nitros getComponent functions will return Accessor!Translation, so if you do this, only int[] for b.x is accessed. foreach(e; ecs.query!Translation) { auto trans = e.getComponent!Translation(); trans.b.x = 0; }You're example almost works. With the EntityComponentManager API it works like this: auto shipEntities = ecm.query!SpaceShip(); foreach (i, spaceship; taskPool.parallel(shipEntities)) { auto shipData = spaceship.getComponent!SpaceShip(); shipData.name = format("Ship %i", i); } Now that unittests are written, documentation is on its way and should be ready in a few days.Ah, so there's no data-orientation here. It's strictly entity-centric. Or do you have a way to iterate components independently of entities?
Feb 07 2014
On Friday, 7 February 2014 at 09:47:43 UTC, Zoadian wrote:On Friday, 7 February 2014 at 08:09:10 UTC, Mike Parker wrote: Nitro will store Translation like this, so it is even possible to iterate over parts of components: Entity[] int[] for a int[] for b.x int[] for b.y int[] for b.z int[] for c.x int[] for c.y int[] for c.zThis looks nice and everything, but won't it slow down access times quite a lot?
Feb 07 2014
Am Fri, 07 Feb 2014 09:58:52 +0000 schrieb "Francesco Cattoglio" <francesco.cattoglio gmail.com>:On Friday, 7 February 2014 at 09:47:43 UTC, Zoadian wrote:Yeah, looks like a point is now spread over 3 cache lines. As long as you access memory strictly forwards or backwards, x86 can at least stream the data from RAM in the background. Now if you check for collisions of 2 objects you'll need up to 6 spread out cache lines, where a compact layout would need one cache-line per object (2). The trouble is that RAM is not only much slower to access, but also it seems to take a while for the data from RAM to arrive in the CPU, making it important to know ahead of time where the next data has to be read from. The combined effect can mean a ~100 times slow down. So x86 got a sophisticated prefetcher, that can track several sequential memory reads (e.g. up to 16) either forwards or backwards through memory and loads those locations into CPU caches before they are needed. If you access pattern is seemingly random to the CPU it might in the worst case still try to prefetch, clogging the memory bandwidth and not achieving anything useful :p. -- MarcoOn Friday, 7 February 2014 at 08:09:10 UTC, Mike Parker wrote: Nitro will store Translation like this, so it is even possible to iterate over parts of components: Entity[] int[] for a int[] for b.x int[] for b.y int[] for b.z int[] for c.x int[] for c.y int[] for c.zThis looks nice and everything, but won't it slow down access times quite a lot?
Feb 07 2014
I've written a coffeescript Entity Component System once(https://github.com/NikkiKoole/ces), I am planning on using https://github.com/elvisxzhou/artemisd for my D needs and I am hoping it's good (and hoping it does the components in some cache friendly manner). how does your nitro compare?
Sep 04 2014
http://t-machine.org/index.php/2014/03/08/data-structures-for-entity-system -contiguous-memory/ has some very nice insights in the memory issue.
Sep 04 2014
Sorry for this belated reply, I have been rather busy with other matters. On Tue, Feb 04, 2014 at 04:12:48AM +0000, digitalmars-d-bounces puremagic.com wrote:I loved reading Walter's component programming article in Dr. Dobb's [0] in late 2012. I had missed H. S. Teoh's mid 2013 article on calendar textual formatting using the component approach [1], but fortunately Ali brought it to my attention recently, and I also find it absolutely fascinating!Thanks!I think what's most interesting with Teoh's article (and I think that was Ali's point when he mentioned the article to me) is that the calendar example is not as an obvious target for the component approach, or at least that the design and implementation is not as obvious for someone new to that approach. Now, while Teoh's example is much more complex than Walter's, both examples are for cases of pipelined problems (source -> filter1 -> filter2 -> sink). What I have been wondering during the last few days is how much this "component programming" approach could be applied to scenarios where you would normally have a jumble of objects. For instance, try to picture a game or simulation where spaceships fire at each other, pick up objects, communicate, and so on, or something like that. My instinct would be to code a solution which would be classified as typical OOP code. Would it be possible to come up with a solution that would be more in the spirit of "component programming"? Or are such solutions only practical/applicable for pipeline-like scenarios?[...] I would say that while it's insightful to apply different paradigms to solve the same problem, one shouldn't make the mistake of shoehorning *everything* into the same approach. This is what Java does with OO, for example, to the detriment of every other paradigm, and frankly, after a while all those singleton classes with static methods just start to smell more and more like ways of working around the OO rather than with it. Having said that, though, the component approach is highly applicable, often in unexpected areas and unexpected ways, esp. when you couple it with D's range-based concept. There are certainly algorithms where it makes more sense to treat your data as a graph rather than a linear sequence of nodes, but it's also true that a good percentage of all code is just variations on linear processing, so pipelined component-style programming would definitely be applicable in many places. And nothing says you can't intermix component-style code with OO, or something else. One key insight is that sometimes you want to separate the object itself from a range over that object -- for example, I work with polytopes (higher-dimensional analogues of polygons and polyhedra), and it's useful to have, say, a range over all vertices, or a range over all edges, but it's also useful to separate these ranges from the polytope itself, which can be stored in a more compact form, or in a form that's more amenable to fast queries, e.g., find all faces that contain vertex X without needing to iterate over every face in the polytope (which you'd end up doing if you use filter() on the range of all faces). The query function can return a range over faces, so that it can be piped into other range-based functions for further processing. Thus, you can have a mix of different paradigms complementing each other. The other underlying theme in my article, which is also one of the key points of the Jackson Structured Programming that I alluded to, is the identification and separation of mismatching structures in order to simplify the code and eliminate code smells caused by ad hoc methods of structure conflict resolution (boolean flags are a common symptom of this malady). This isn't limited to pipelined programs, but applies in general. One could analyze OOP in this way, for example. OO lore says that objects should be cohesive and loosely-coupled -- we could say that cohesiveness means that the data stored in the object has corresponding structures, and loose coupling means that if an object's data has conflicting structures, it's time to consider splitting it into two different objects instead. T -- I've been around long enough to have seen an endless parade of magic new techniques du jour, most of which purport to remove the necessity of thought about your programming problem. In the end they wind up contributing one or two pieces to the collective wisdom, and fade away in the rearview mirror. -- Walter Bright
Feb 12 2014
Dear T, I've read with a great attention your reply regarding ECS and OOP. You mention that you work on high-dimensional polytope and a data structure able to support fast topological query with compact storage. I would be very interested in having a look to your data structure. Do you have any document about your design and the concepts? Any github? This thred is really extremely instructive. I m looking forward to reading your reply. Regards, - David - On Wednesday, 12 February 2014 at 17:38:30 UTC, H. S. Teoh wrote:Sorry for this belated reply, I have been rather busy with other matters. On Tue, Feb 04, 2014 at 04:12:48AM +0000, digitalmars-d-bounces puremagic.com wrote:I loved reading Walter's component programming article in Dr. Dobb's [0] in late 2012. I had missed H. S. Teoh's mid 2013 article on calendar textual formatting using the component approach [1], but fortunately Ali brought it to my attention recently, and I also find it absolutely fascinating!Thanks!I think what's most interesting with Teoh's article (and I think that was Ali's point when he mentioned the article to me) is that the calendar example is not as an obvious target for the component approach, or at least that the design and implementation is not as obvious for someone new to that approach. Now, while Teoh's example is much more complex than Walter's, both examples are for cases of pipelined problems (source -> filter1 -> filter2 -> sink). What I have been wondering during the last few days is how much this "component programming" approach could be applied to scenarios where you would normally have a jumble of objects. For instance, try to picture a game or simulation where spaceships fire at each other, pick up objects, communicate, and so on, or something like that. My instinct would be to code a solution which would be classified as typical OOP code. Would it be possible to come up with a solution that would be more in the spirit of "component programming"? Or are such solutions only practical/applicable for pipeline-like scenarios?[...] I would say that while it's insightful to apply different paradigms to solve the same problem, one shouldn't make the mistake of shoehorning *everything* into the same approach. This is what Java does with OO, for example, to the detriment of every other paradigm, and frankly, after a while all those singleton classes with static methods just start to smell more and more like ways of working around the OO rather than with it. Having said that, though, the component approach is highly applicable, often in unexpected areas and unexpected ways, esp. when you couple it with D's range-based concept. There are certainly algorithms where it makes more sense to treat your data as a graph rather than a linear sequence of nodes, but it's also true that a good percentage of all code is just variations on linear processing, so pipelined component-style programming would definitely be applicable in many places. And nothing says you can't intermix component-style code with OO, or something else. One key insight is that sometimes you want to separate the object itself from a range over that object -- for example, I work with polytopes (higher-dimensional analogues of polygons and polyhedra), and it's useful to have, say, a range over all vertices, or a range over all edges, but it's also useful to separate these ranges from the polytope itself, which can be stored in a more compact form, or in a form that's more amenable to fast queries, e.g., find all faces that contain vertex X without needing to iterate over every face in the polytope (which you'd end up doing if you use filter() on the range of all faces). The query function can return a range over faces, so that it can be piped into other range-based functions for further processing. Thus, you can have a mix of different paradigms complementing each other. The other underlying theme in my article, which is also one of the key points of the Jackson Structured Programming that I alluded to, is the identification and separation of mismatching structures in order to simplify the code and eliminate code smells caused by ad hoc methods of structure conflict resolution (boolean flags are a common symptom of this malady). This isn't limited to pipelined programs, but applies in general. One could analyze OOP in this way, for example. OO lore says that objects should be cohesive and loosely-coupled -- we could say that cohesiveness means that the data stored in the object has corresponding structures, and loose coupling means that if an object's data has conflicting structures, it's time to consider splitting it into two different objects instead. T
Sep 04 2014
Sorry for the very late reply; my internet connection was down for 2 weeks and only came back yesterday. On Thu, Sep 04, 2014 at 08:03:51AM +0000, David Ledez via Digitalmars-d wrote:Dear T, I've read with a great attention your reply regarding ECS and OOP. You mention that you work on high-dimensional polytope and a data structure able to support fast topological query with compact storage. I would be very interested in having a look to your data structure. Do you have any document about your design and the concepts? Any github?I'm sorry to disappoint, but I was merely alluding to the fact that separating the range-based interface from the container allows one to freely choose the most suitable structure to represent the polytope, while using a proxy type to expose a range interface to allow generic algorithms to work with it. My code is currently still very much a work in progress, and I don't really have very much to show for it yet. The basic design, however, is along these lines: - A Polytope interface representing any abstract polytope-like structure in the program (see below for details); - A ConcretePolytope class (implementing a Polytope) that stores a face lattice, represented as a graph, the nodes of which are obtained by running a convex hull + lattice enumeration algorithm on the source data. - The Polytope interface has abstract methods for enumerating sub-polytopes (as input/forward ranges), which concrete classes like ConcretePolytope implement; the idea being that a face of a Polytope is also a Polytope, and while the underlying implementation may be different (e.g., the range of Polytopes representing the (n-1)-dimensional facets may have a different representation from, say, the 1-dimensional edges), they implement the same interface so generic algorithms can work with them without special-casing. This is, of course, just plain old OO, except perhaps for the range API part. The sub-polytope enumeration methods return proxy types that implement the range API, with Polytope as the element type, so you can use the usual std.algorithm / std.range tools on them -- .find, .filter, .chain, .cycle, .takeN, etc.. The proxy types are themselves interfaces, meaning that you can write a proxy Polytope implementation that performs some complex query over the lattice structure of ConcretePolytope, and still present a nice range API over its elements, and you can pass this to any of the usual range-based algorithms for searching, filtering, composing, etc., with no code change required in the algorithms. Again, this is just plain ole OO (Liskov substitution, in particular), seasoned with some D-flavored range-styled code. So you could, in theory ('cos I haven't actually implemented this part yet), construct some complex query over the polytope, and ask the program to enumerate, say, all 5D faces subject to some given filter, say they must have a certain number of 3D subfaces. In code, it could be as simple as: ConcretePolytope p = ...; auto query = new PolyQuery(...) // construct complex proxy Polytope from p // The query proxy object is still a Polytope assert(is(typeof(query) : Polytope)); query.faces(5) // get range of faces of dimension 5 .filter!((p) => p.faces(3).count > 10) // filter by faces with more than 10 3D faces .copy((p) { // print a list of face ID's in the result writefln("%s", p.id); }); Notice how the second block of code can actually apply directly to ConcretePolytope (since it implements the Polytope interface), or to a PolyQuery object (which represents some subset of the ConcretePolytope's surface), or to anything, really, that implements the Polytope interface -- perhaps a specific face of a ConcretePolytope. Due to the range API implemented by the .faces method, you can then process this range downstream using all of the usual range-based algorithms. Also note that by abstracting the implementation details of ConcretePolytope away, it is also possible to implement a different kind of concrete polytope, say one where the full face lattice isn't computed beforehand, like I'm doing now, but which is lazily computed depending on what kind of queries you run on it -- i.e., if you call faces(6), then it will lazily construct the 6-dimensional faces of the polytope on the fly as you iterate over the range, and if you iterate over, say, the 5-dimensional faces of a subset of the 6D faces, then the lattice enumeration algorithm will only be run for those subset of faces, rather than the entire polytope. As you probably know, the face lattice of a general polytope can be exponential in the size of its initial vertex/hyperplane representation, so allowing this kind of lazy evaluation *without needing to change any downstream code* is a big advantage. It is also possible to implement a polytope whose faces are mathematically-generated, allowing compact storage. For example, you could generate it from a symmetry group, which alleviates the need to store all vertices / hyperplanes (you can generate everything from the vertex figures, for example). Again, none of the downstream code needs to change; they will Just Work(tm). This isn't anything radically new, really, it's just basic OO design, but just with a little range-based spice added to it. :) T -- They say that "guns don't kill people, people kill people." Well I think the gun helps. If you just stood there and yelled BANG, I don't think you'd kill too many people. -- Eddie Izzard, Dressed to Kill
Sep 10 2014
On Wednesday, 12 February 2014 at 17:38:30 UTC, H. S. Teoh wrote:I would say that while it's insightful to apply different paradigms to solve the same problem, one shouldn't make the mistake of shoehorning *everything* into the same approach. This is what Java does with OO, for example, to the detriment of every other paradigm, and frankly, after a while all those singleton classes with static methods just start to smell more and more like ways of working around the OO rather than with it.I found myself using singelton classes more and more until I decided it was time to drop a strict OO approach.Having said that, though, the component approach is highly applicable, often in unexpected areas and unexpected ways, esp. when you couple it with D's range-based concept. There are certainly algorithms where it makes more sense to treat your data as a graph rather than a linear sequence of nodes, but it's also true that a good percentage of all code is just variations on linear processing, so pipelined component-style programming would definitely be applicable in many places. And nothing says you can't intermix component-style code with OO, or something else.That's what I've been doing for the last 1 1/2 years. I use classes where it makes _sense_, not as the ruling paradigm, then add structs (components), ranges and templates. The good thing about the freedom D offers is that it encourages you to think about the fundamental logic of your program and use tailor made solutions for a given problem - instead of a one size fits all approach that is bound to lead you down a cul de sac. In a way D has given the power back to the programmer's brain.One key insight is that sometimes you want to separate the object itself from a range over that object -- for example, I work with polytopes (higher-dimensional analogues of polygons and polyhedra), and it's useful to have, say, a range over all vertices, or a range over all edges, but it's also useful to separate these ranges from the polytope itself, which can be stored in a more compact form, or in a form that's more amenable to fast queries, e.g., find all faces that contain vertex X without needing to iterate over every face in the polytope (which you'd end up doing if you use filter() on the range of all faces). The query function can return a range over faces, so that it can be piped into other range-based functions for further processing. Thus, you can have a mix of different paradigms complementing each other. The other underlying theme in my article, which is also one of the key points of the Jackson Structured Programming that I alluded to, is the identification and separation of mismatching structures in order to simplify the code and eliminate code smells caused by ad hoc methods of structure conflict resolution (boolean flags are a common symptom of this malady). This isn't limited to pipelined programs, but applies in general. One could analyze OOP in this way, for example. OO lore says that objects should be cohesive and loosely-coupled -- we could say that cohesiveness means that the data stored in the object has corresponding structures, and loose coupling means that if an object's data has conflicting structures, it's time to consider splitting it into two different objects instead. T
Sep 04 2014
On Thursday, 4 September 2014 at 10:12:13 UTC, Chris wrote:On Wednesday, 12 February 2014 at 17:38:30 UTC, H. S. Teoh wrote:In Smalltalk and Eiffel, where everything is an object this tends not to be a problem, because they lack modules anyway. So objects with class methods play the role of modules in a way package support, it would be more natural to associate certain code with the package, not with objects. be encapsulated into a (dummy) class, for example.I would say that while it's insightful to apply different paradigms to solve the same problem, one shouldn't make the mistake of shoehorning *everything* into the same approach. This is what Java does with OO, for example, to the detriment of every other paradigm, and frankly, after a while all those singleton classes with static methods just start to smell more and more like ways of working around the OO rather than with it.I found myself using singelton classes more and more until I decided it was time to drop a strict OO approach.This was actually my first issue when I learned OO in Turbo Pascal 5.5, my first OO language. It was a learning process to understand what should become an object, and what should stay as usual procedural (functions/records/units) code. Regarding component programming in general, this used to be a good book on the subject. Only read the first edition (based in Component Pascal), the second was updated to more "modern" languages. http://www.amazon.com/Component-Software-Object-Oriented-Programming-Addison-Wesley/dp/032175302X -- PauloHaving said that, though, the component approach is highly applicable, often in unexpected areas and unexpected ways, esp. when you couple it with D's range-based concept. There are certainly algorithms where it makes more sense to treat your data as a graph rather than a linear sequence of nodes, but it's also true that a good percentage of all code is just variations on linear processing, so pipelined component-style programming would definitely be applicable in many places. And nothing says you can't intermix component-style code with OO, or something else.That's what I've been doing for the last 1 1/2 years. I use classes where it makes _sense_, not as the ruling paradigm, then add structs (components), ranges and templates. The good thing about the freedom D offers is that it encourages you to think about the fundamental logic of your program and use tailor made solutions for a given problem - instead of a one size fits all approach that is bound to lead you down a cul de sac. In a way D has given the power back to the programmer's brain.
Sep 04 2014