Project V: Listing Types
Saturday, 25. October 2008, 19:07:08

Just a little recap as to how types are defined in Project V. There are three kinds of entities.
1. Types
2. Modifiers
3. Instances
A type is the most powerful and flexible entity. It contains sets. In the above screenshot, you can see a type by the name of Integer. It has one set called Properties. The Properties set is special in that it defines the meaning of the type itself. You can see three of those properties: Size, Signed and Endian. As you can see, we have defined a 4 byte signed integer that is stored in little endian order. Simply use or create a type with different properties to get a different kind of integer.
The last line is MyInteger. This is a derived entity from the Integer type. Since it has a value (22), we can infer that it is an instance. So by creating an instance entity and deriving it from a specific type, we create an instance of that type. From the properties, the IDE knows that 22 takes up 4 bytes, is signed and is stored in little endian order.
To really screw with your head, consider that each of the properties are also instances and are defined exactly like MyInteger is defined. Note that the size property has a base type of Integer of which it is helping to define. In Project V, circular type definitions like this are no problem.
Here is C++ style pseudo code to explain the Size property.
class Integer
{
Properties: // Imagine this defines a set
Integer Size=4;
Bool Signed=TRUE;
Endian Endian=little;
} MyInteger = 22;
(Heck, I may allow users to create type definitions in this manner. Look at the Size property again. If Size is itself an instance, what is the size of it and what property defines it? Answer: itself!)
So far I've explained types and instances. But what about modifiers? Modifiers and instances are almost identical. While types can have many other base types, modifiers and instances can only have one direct base type. And the only difference between modifiers and instances is that a modifier will not create an instance. So you can use a modifier to override properties in base types. In fact, MyInteger is derived from the Int32 modifier which contains the properties you see in the screenshot above. And the typename of MyInteger would be Int32, NOT Integer as that is further up the hierarchy.
Here is really what's going on.
type Integer
{
Properties: // Imagine this defines a set
Integer Size;
Bool Signed;
Endian Endian;
}
modifier Int32 : Integer
{
// Override the Properties set in the Integer type
Properties(Integer):
Size = 4;
Signed = TRUE;
Endian = little;
}
type Enum
{
// The Options set will contain the items of the enumeration.
Options:
}
type Bool : Int32, Enum
{
// Override the Options set in Enum.
Options(Enum):
Bool FALSE = 0;
Bool TRUE = 1;
}
type Endian : Int32, Enum
{
// Override the Options set in Enum.
Options(Enum):
Endian little = 0;
Endian big = 1;
}
Int32 MyInteger = 22;
So how should I show the typename of all the properties? Most property editors don't show it at all. I don't really want to widen the treeview to display this information. A rollover popup might be good. However, I'm not sure what's the best way to go. Any suggestions? Maybe I could toggle it on or off and display instances as "Int32:MyInteger". I'm still not sure.
I'll be working on connecting components together next. I'll have to display instances and its type hierarchy as well. Moreso than what's in the screenshot above. That's mostly for updating existing data structures and values.
So what should be the very first component to show itself in Project V? Addition? Or maybe a more esoteric component? And if there are suggestions for built-in components, let me know. Right now, I have this potential list (which will only work on integers to start off until I can make generic versions).
Multiplexor
Demultiplexor
Compare !=
Compare ==
Compare <=
Compare <
Compare >=
Compare >
And
Or
Xor
Not
Div (two outputs. Quotient and Remainder)
Mul
Subtraction
Addition
The multiplexor and demultiplexor are required as this is how you select where data goes. But if I didn't care about speed, I could build them out of the other components.
The Demultiplexor takes two inputs (and has two outputs although only one output is activated at a time). The first input is a boolean selector that selects what output to send the input. So there are two outputs named TRUE and FALSE which are activated depending on the state of the selector.
The Multiplexor has three inputs and one output. It again has a boolean selector and chooses either the input with the label of TRUE or FALSE depending on its state. The selected input is sent out on the output and the other value is discarded.
I'm thinking of building a swap component based on a selector instead of the multiplexor. Three inputs and two outputs. Basically two inputs are sent directly to two corresponding outputs if the selector is FALSE. If the selector is TRUE, then the inputs are swapped. That may be more useful than a multiplexor. If you don't use the second output, you can simply leave it unconnected and you have exactly the same functionality as a multiplexor.
And believe it or not, you can build anything and everything possible with that setup though I wouldn't recommend using such low level components for actual software development.
That would make a total of 16 components, many of which can be built from a subset of that same list. Actually, you only need two components to build anything you want. A NOT component and your choice of AND or OR component. You decide which one you want. In fact, you could combine them and only have ONE component (NAND or NOR). So it's not the computations that are critical. It's the ability to link those computations together. That's where the power comes from.


Anonymous # 26. October 2008, 00:38
You may already have read this, but you may be interested in Steve Yegge's lastest post about the "Prototype Pattern" which seems to be similar to how you have done your type system within Project V where, if I am not mistaken, you support the definition of new types by just changing the properties of an existing type/value and giving it a new name.
Vorlath # 26. October 2008, 01:39
Just on inheritance, the code I showed above is exactly what is quoted here from your link.
I do it a bit different. I use sets instead of having global property names. And those sets are attached to a particular object. The reason for this is multiple inheritance. I want to be able to specify which parent object's properties I am overriding. So you can separately override two different sets that have the same name in two different parent objects.
The inherited property lookup is somewhat like what is described in the quote above except I go one further. I can flatten hierarchy trees so that all properties are directly accessible. After flattening a hierarchy, I can simply lookup the property directly. No need to search upwards. The drawback is that flattening a hierarchy needs to be done again every time a property changes. I'm going to be adding a way to identify hierarchies by SHA ID. That's next up on the list. This will provide fast type lookups instead of comparing each and every property to find out if two types are identical.
and from my actual code inside my "object" definition,
And then there's this:
My screenshot above is showing exactly this! You can't see the editor in action (like when I change 22 to something else), but when you apply a value, it sets it on the local object.
See NENTRY_FLAGS_LOCK above.
Strange, I created this type system because I wanted performance.
I have a class called NID just for that purpose. I actually use it for two purposes. The first it to identify 'type' entities. And the other is to reduce frozen hierarchies to an ID for faster type comparisons.
I also have the advantage that some properties are design time only and affect type comparisons and other properties that are runtime members and do not affect type comparisons. So I don't have the same drawbacks mentioned in the article. I can change members at runtime without recalculating the ID.
I use what is called an XTYPE as a flattened cache.
I guess I should start praying?
Yeah, I ran into this problem very quickly. That's why I started with two sets (or property lists). Properties and Members. Properties are designtime and Members are runtime. But as we all know in programming, if you can have two, you can have as many as you want. So you can now have as many sets as you'd like and you can specify if they are runtime or design time. They also allow other attributes like storing objects directly instead of name/value pairs. That's how the type hierarchy is done. Each object has a Derived and Base set.
Already done.
Yeah, I kinda figured that one out the hard way.
Already have a solution for this. I have remapping constructs that enable the replacement of existing types and components. It's necessary because of the data flow system. I suppose Steve doesn't need data flow, so his hand hasn't been forced.
Well, all I can say is that if anyone is interested in having a system that uses the Prototype pattern, Project V will be one such option. This is true even if you don't care about the concurrent and distributed functionality available in it through the use of dataflow.