Skip to main content
GameDev.net gamedev.net
🔒 Locked

I present, for your inspection, Kaleidoscope

Started by _goat Jun 18, 2006 at 1:03 PM 5 replies 1.9k views
Original Post
_goat
_goat
Warning: Long Content Well, I got sidetracked by being unable to do something in C++, and this was the result. I didn't feel like I could put this to you guys as Epoch - that wouldn't be very fair, so instead I have named it Kaleidoscope. This is a long document! I hope you enjoy it. I hope you read it. I'm sure you would do things differently too, but I figured we needed something concrete after so many pages of blabbering. Edit: I've structured it in such a way that you can start reading at the top, and not meet any material that makes more than a brief mention of material we haven't yet covered. In other words, it builds up from what most of you would know, to the whole language.

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Overview</font>
	<font color=green>//  ----------</font>
	<font color=green>//    This document turned out to be a lot longer than I originally</font>
	<font color=green>//    intended - and there's still stuff left to write. I am very</font>
	<font color=green>//    proud of this work, as I feel I've captured many aspects of what</font>
	<font color=green>//    people are looking for - considerations on speeed, lambda functions,</font>
	<font color=green>//    dynamic typing, static typing, templating, garbage collection,</font>
	<font color=green>//    heirarchy of types, etc.</font>
	<font color=green>//</font>
	<font color=green>//    However, I'm no language expert. What I've done here is to</font>
	<font color=green>//    define the rules of the language. Hopefully, one of you will read</font>
	<font color=green>//    through this, and tell me if what I'm proposing is sound. I suspect</font>
	<font color=green>//    most of it is, although I'm confident there are going to be syntax</font>
	<font color=green>//    ambiguities that I've missed, although I've designed it in a way</font>
	<font color=green>//    to reduce those possibilities.</font>
	<font color=green>//</font>
	<font color=green>//    This is a work-in-progress, so feel free to make suggestions, etc.</font>
	<font color=green>//    I'm very happy with the fundamental structure of the language, but</font>
	<font color=green>//    things like references, the "singular use of concepts" rule - small</font>
	<font color=green>//    things that potentially make the language harder (or just "more" to</font>
	<font color=green>//    store in your head) I'm totally good for changing.</font>
	<font color=green>//</font>
	<font color=green>//    There are some things I haven't even mentioned, such as the</font>
	<font color=green>//    compilation model, preprocessor directives, and whether or not this</font>
	<font color=green>//    is run on a VM or compiled straight (I favour both). In these cases</font>
	<font color=green>//    feel free to offer suggestions on what would compliment the</font>
	<font color=green>//    language.</font>
	<font color=green>//</font>
	<font color=green>//    Also, if the implementation of dynamic-typing & static-typing (and</font>
	<font color=green>//    no, I'm not talking about the side-by-side examples which would</font>
	<font color=green>//    more than likely have name resolution ambiguities) is utterly</font>
	<font color=green>//    impossible via some rules of compilation theory, inform a moderator</font>
	<font color=green>//    quickly to remove the thread so I don't look so foolish. :)</font>
	<font color=green>//</font>
	<font color=green>//    Finally, I'd like to note, and this happened quite by accident, that</font>
	<font color=green>//    I seem to have followed the "if you don't use it, you don't pay for</font>
	<font color=green>//    it" mantra. This is realised through the use of a great many more</font>
	<font color=green>//    keywords/paradigms than most other languages, and as such it should</font>
	<font color=green>//    be obvious that one can write damn near identical code as C code,</font>
	<font color=green>//    and as such should be very fast. That is, of course, by -not- using</font>
	<font color=green>//    dynamic typing, automatic memory management, expressions or</font>
	<font color=green>//    concepts.</font>
	<font color=green>//</font>
	<font color=green>//    I actually had my own mantra when I set out, "make it ridiculously</font>
	<font color=green>//    powerful, but make the default values for everything good enough</font>
	<font color=green>//    for 90% of the work". That way, beginners can use and abuse it, and</font>
	<font color=green>//    experts can modify everything as they require. It's a little like</font>
	<font color=green>//    people using C++'s std::vector, and never actually thinking, "what</font>
	<font color=green>//    does 'allocater<_T>' mean?".</font>
	<font color=green>//</font>
	<font color=green>//    Anyway, grab some coffee or something - it's long.</font>
	<font color=green>//</font>
	<font color=green>//                                         - Jonathan, 19th June, 2006</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Primitives</font>
	<font color=green>//  ------------</font>
	<font color=green>//    I went with a suggested form of primitives, where we have integer,</font>
	<font color=green>//    boolean, and real (and possibly complex??) as primitives. Both</font>
	<font color=green>//    integer and real have a language-defined extension, allowing us to</font>
	<font color=green>//    specify the size (to avoid the C++ "long long" problem). They are</font>
	<font color=green>//    used as such:</font>
	<font color=green>//      integer<32> a_long;</font>
	<font color=green>//      integer<16> a_short;</font>
	<font color=green>//      integer<8> a_char;</font>
	<font color=green>//      integer<128> a_long_long_long?;</font>
	<font color=green>//      real<32> a_float;</font>
	<font color=green>//      real<64> a_double;</font>
	<font color=green>//      real<128> a_quadruple?;</font>
	<font color=green>//</font>
	<font color=green>//    To make things easier, there is a compiler-defined default value,</font>
	<font color=green>//    which for machines currently would probably be 32, and 64 very</font>
	<font color=green>//    soon. It's up to compiler-people if they allow you to change this</font>
	<font color=green>//    via compiler-settings. If you use the default, you can omit the</font>
	<font color=green>//    whole "<xx>" part (and just use "integer").</font>
	<font color=green>//</font>
	<font color=green>//    Furthermore, the integer primitive has the "unsigned" flag which</font>
	<font color=green>//    can precede it. You know how it works - I won't go over it. The</font>
	<font color=green>//    formal definitions are:</font>
	<font color=green>//</font>
	<font color=green>//      - [ unsigned ] integer [ <X> ] "variable-name" ;</font>
	<font color=green>//      - real [ <X> ] "variable-name" ;</font>
	<font color=green>//      - boolean "variable-name" ;</font>
	<font color=green>//</font>
	<font color=green>//    All those primitives belong to the "number" concept. See below</font>
	<font color=green>//    for "concepts".</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Typedefing (Aliasing)</font>
	<font color=green>//  ------------</font>
	<font color=green>//    Typedefing is exactly the same as in C++, with the change of the</font>
	<font color=green>//    keyword to "alias". In this case, I'm aliasing "unsigned integer"</font>
	<font color=green>//    with "uint" for ease of typing.</font>
	<font color=green>//</font>
	<font color=green>//    Note: Since "uint" is only an alias for "unsigned integer", we can</font>
	<font color=green>//          still use it like "uint<32>", or "uint<64>" or what-have-you.</font>
	<font color=green>//          If we had declared it as "alias unsigned integer<32> uint",</font>
	<font color=green>//          we would not have that option.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	<font color=blue>alias</font> <font color=blue>unsigned</font> <font color=blue>integer</font> uint;
	
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Added Keywords</font>
	<font color=green>//  ----------------</font>
	<font color=green>//    I say "added", because I haven't seen these in C/C++/Java/C#/VB,</font>
	<font color=green>//    they more than likely exist somewhere.</font>
	<font color=green>//</font>
	<font color=green>//    autotype</font>
	<font color=green>//    ----------</font>
	<font color=green>//      Replaces C++'s "auto" - keeping in line with naming conventions</font>
	<font color=green>//</font>
	<font color=green>//    for_count( "unsigned-integer" ) {   }</font>
	<font color=green>//    --------------</font>
	<font color=green>//      Takes an unsigned integer and loops that many times. Unsure</font>
	<font color=green>//      about including it (but why not?).</font>
	<font color=green>//</font>
	<font color=green>//    alias</font>
	<font color=green>//    -------</font>
	<font color=green>//      Replaces "typedef", as written above.</font>
	<font color=green>//</font>
	<font color=green>//    typeof( "variable" )</font>
	<font color=green>//    ------------</font>
	<font color=green>//      Returns the type of a variable, via a datatype_jar. See "Jars"</font>
	<font color=green>//      for more information. It is fairly self-explanatory in the</font>
	<font color=green>//      examples (and only has one use).</font>
	<font color=green>//</font>
	<font color=green>//    muud( "variable" )</font>
	<font color=green>//    ----------</font>
	<font color=green>//      Returns the boolean result of the expression </font>
	<font color=green>//</font>
	<font color=green>//        typeof(the_variable) == mu</font>
	<font color=green>//</font>
	<font color=green>//      See "The Mu-Type" for more information.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Namespaces</font>
	<font color=green>//  ------------</font>
	<font color=green>//    I really like namespaces in C++ - I think they're far cleaner than</font>
	<font color=green>//    modules in Java, especially since we're going to be allowing</font>
	<font color=green>//    functions to be running around by themselves.</font>
	<font color=green>//</font>
	<font color=green>//    However, I don't think they're powerful enough. As it stands in C++,</font>
	<font color=green>//    any variables declared in a namespace are global, albiet global in</font>
	<font color=green>//    that namespace. I think there should be the ability to have datatypes</font>
	<font color=green>//    and variables that can be declared private in a namespace, so only</font>
	<font color=green>//    classes and functions of that namespace can access them. It would</font>
	<font color=green>//    certainly help with modularity.</font>
	<font color=green>//</font>
	<font color=green>//    Thus:</font>
	<font color=green>//</font>
	<font color=green>//      namespace "namespace-name"</font>
	<font color=green>//      {</font>
	<font color=green>//         [private | protected | public] "member"; // repeated</font>
	<font color=green>//      }</font>
	<font color=green>//</font>
	<font color=green>//    Where "public" is the default permission.</font>
	<font color=green>//    I have yet to decide if the planned functionality for the "protected"</font>
	<font color=green>//    permission will go ahead. Maybe?</font>
	<font color=green>//</font>
	<font color=green>//    "ksl" is the Kaleidoscope Standard Library. :P</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// not accessable for anything declared outside the KSL.</font>
			<font color=blue>private</font> <font color=blue>const</font> <font color=blue>real</font> KSLVersion = 0.1;
			<font color=green>// accessable by default</font>
			<font color=blue>const</font> <font color=blue>real</font> KSL_Happiness_Level = 7;
		}

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Functions</font>
	<font color=green>//  -----------</font>
	<font color=green>//    I'll give the formal definition first:</font>
	<font color=green>//</font>
	<font color=green>//      [inline | static | const | virtual ] function "return-type" "function-name"</font>
	<font color=green>//               [ < "datatype-list" > ]</font>
	<font color=green>//               ( [ "parameter-list" ] )</font>
	<font color=green>//               [ where ( "expression" ) ]</font>
	<font color=green>//               {</font>
	<font color=green>//               }</font>
	<font color=green>//</font>
	<font color=green>//    Modifiers</font>
	<font color=green>//    -----------</font>
	<font color=green>//      inline, static, const and virtual modifiers are placed before the "function"</font>
	<font color=green>//      declaration. Their usage is just like C++.</font>
	<font color=green>//</font>
	<font color=green>//    Compile-Time Templates</font>
	<font color=green>//    ------------------------</font>
	<font color=green>//      Kaleidoscope offers compile-time templating, with the typenaming occuring</font>
	<font color=green>//      after the function name, like so:</font>
	<font color=green>//</font>
	<font color=green>//        function T add<datatype T>(const T& t1, const T& t2)</font>
	<font color=green>//        {</font>
	<font color=green>//            return t1 + t2;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      The datatype keyword is covered later. For now, it has the same usage</font>
	<font color=green>//      (and even meaning) of "typename", or "class" as in templates.</font>
	<font color=green>//</font>
	<font color=green>//    Validation</font>
	<font color=green>//    ------------</font>
	<font color=green>//      Validation occurs after the parameter list, and is an expression that</font>
	<font color=green>//      evaluates to a boolean value, like so:</font>
	<font color=green>//</font>
	<font color=green>//        function T add<datatype T>(const T& t1, const T& t2) where (t1 < 17)</font>
	<font color=green>//        {</font>
	<font color=green>//            return t1 + t2;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      In the above case, the validation only makes sense if T has a less-than</font>
	<font color=green>//      operator, taking a number. </font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>

		<font color=green>//=====================================================================</font>
		<font color=green>// Real World(tm) Examples</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=blue>function</font> <font color=blue>void</font> copy_memory(<font color=blue>void</font> * destination, <font color=blue>void</font> * source, uint size) <font color=blue>where</font> (dest && source)
			{
				<font color=blue>for</font> (uint i = 0; i < size; ++i)
				{
					<font color=blue>reinterpret_cast</font><<font color=blue>integer</font><8>*>(dest) = <font color=blue>reinterpret_cast</font><<font color=blue>integer</font><8>*>(source);
				}
			}
			
			<font color=blue>function</font> <font color=blue>void</font> set_memory(<font color=blue>void</font> * dest, uint size, <font color=blue>integer</font><8> value = 0) <font color=blue>where</font> (dest)
			{
				<font color=blue>for</font> (uint i = 0; i < size; ++i)
				{
					<font color=blue>reinterpret_cast</font><<font color=blue>integer</font><8>*>(dest) = value;
				}
			}

			<font color=blue>function</font> uint strlen(<font color=blue>const</font> char * s) <font color=blue>where</font> (s)
			{
				uint length = 0;
				<font color=blue>for</font> (uint i = 0; s != '0'; ++i) ++length;
				<font color=blue>return</font> length;
			}
		}

	<font color=green>//=====================================================================</font>
	<font color=green>// </font>
	<font color=green>//  The Mu-Type</font>
	<font color=green>//  -------------</font>
	<font color=green>//</font>
	<font color=green>///   Pinching mu from ApochPiQ, it signifies a variable whose datatype</font>
	<font color=green>//    is changable. It signifies the "null-type" datatype for dynamic</font>
	<font color=green>//    types. Indeed it is used in two contexts. I do not find this</font>
	<font color=green>//    counter-inuitive at all, quite the opposite, actually.</font>
	<font color=green>//</font>
	<font color=green>//    mu [ < "access-list" > ] "variable-name" [ < "initial-type" > ] ;</font>
	<font color=green>//</font>
	<font color=green>//    mu is very similar to "void", except that it can be typed, and the </font>
	<font color=green>//    typing is persistant. The type can be changed again at a later time, </font>
	<font color=green>//    and that change too is persistant. Any operation on a mu-type while </font>
	<font color=green>//    it's still initialised to mu is illegal. Note: typeof( ) can still</font>
	<font color=green>//    be used on mu-types which are uninitialised, which will of course</font>
	<font color=green>//    return mu.</font>
	<font color=green>//</font>
	<font color=green>//    mu-types can be set back to "mu" as a sort of null-state.</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Initialisation</font>
	<font color=green>//    ----------------</font>
	<font color=green>//      The default initialisation of mu is mu. This means with</font>
	<font color=green>//</font>
	<font color=green>//        mu my_name;</font>
	<font color=green>//</font>
	<font color=green>//      my_name's type is initially mu, which could be found with a</font>
	<font color=green>//      typeof(my_name). This, hwoever, can be changed, with the default</font>
	<font color=green>//      initialisation been defined at compile time, like so:</font>
	<font color=green>//</font>
	<font color=green>//        mu my_name<string>;</font>
	<font color=green>//</font>
	<font color=green>//      Here, declaring a dynamic variable who's initial type is type string,</font>
	<font color=green>//      but which can change at a later point in time, directly like so:</font>
	<font color=green>//</font>
	<font color=green>//        mu my_name;</font>
	<font color=green>//        my_name<string>; // set type</font>
	<font color=green>//</font>
	<font color=green>//      They can be assigned another variable, like so:</font>
	<font color=green>//</font>
	<font color=green>//        mu my_name;</font>
	<font color=green>//        string fred = "fred";</font>
	<font color=green>//        my_name = fred;</font>
	<font color=green>//      </font>
	<font color=green>//      There is enough information to type my_name and then assign it</font>
	<font color=green>//      a value. Ambiguities can be picked up at compile-time:</font>
	<font color=green>//</font>
	<font color=green>//        mu my_age;</font>
	<font color=green>//        my_age = 4; // unsigned, signed, 32-bits, 16 bits??</font>
	<font color=green>//</font>
	<font color=green>//      and can be explicitly typed:</font>
	<font color=green>//      </font>
	<font color=green>//        mu my_age;</font>
	<font color=green>//        my_age<unsigned integer> = 4;</font>
	<font color=green>//        my_age = real<32>(4.2);</font>
	<font color=green>//        my_age(real<128>(203958230985.3));</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Permissions</font>
	<font color=green>//    -------------</font>
	<font color=green>//      There may be cases where we might want a dynamic type to be exposed</font>
	<font color=green>//      publicly to the user, but have them unable to change its type. This</font>
	<font color=green>//      can be achieved via permissions (although I should note that it's</font>
	<font color=green>//      probably a design flaw):</font>
	<font color=green>//</font>
	<font color=green>//        datatype Cat</font>
	<font color=green>//        {</font>
	<font color=green>//            public mu<Cat> Name<string>;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      Here, only members and methods in the scope of Cat can change the the</font>
	<font color=green>//      type of Name, but it is still publicly accessable to anyone. This can</font>
	<font color=green>//      be limited to a range of functions, such as:</font>
	<font color=green>//</font>
	<font color=green>//      datatype Animal</font>
	<font color=green>//      {</font>
	<font color=green>//          public mu<speak, run> State<string>;</font>
	<font color=green>//</font>
	<font color=green>//          public virtual function speak();</font>
	<font color=green>//          public virtual function run();</font>
	<font color=green>//      }</font>
	<font color=green>//</font>
	<font color=green>//      The default is global type-changing.</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Parameters</font>
	<font color=green>//    ------------</font>
	<font color=green>//      A mu-type as a parameter allows any datatype to be passed in. Thus</font>
	<font color=green>//      the function:</font>
	<font color=green>//</font>
	<font color=green>//        function boolean equals_3(const mu& m)</font>
	<font color=green>//        {</font>
	<font color=green>//            return m == 3;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      will accept any type, and compare that value to three. To know the</font>
	<font color=green>//      type that was passed in, a simple typeof( ) can be used on the</font>
	<font color=green>//      variable, both in the function, and in the validation:</font>
	<font color=green>//</font>
	<font color=green>//        function boolean equals_3(const mu& m) where (typeof(m) != ksl::string)</font>
	<font color=green>//        {</font>
	<font color=green>//            return m == 3;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      Now the function accepts any type except ksl::string. Or perhaps</font>
	<font color=green>//      more usefully:</font>
	<font color=green>//</font>
	<font color=green>//        function boolean equals_3(const mu& m)</font>
	<font color=green>//        {</font>
	<font color=green>//            if (typeof(m) == ksl::string) return m == "3";</font>
	<font color=green>//            return m == 3;</font>
	<font color=green>//        }</font>
	<font color=green>//    </font>
	<font color=green>//      Note: Clearly, scoping permissions can not be used in parameters.</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Default Parameter Type</font>
	<font color=green>//    ------------------------</font>
	<font color=green>//      The default parameter type is "mu&". That means:</font>
	<font color=green>//</font>
	<font color=green>//        function void print_stuff(x)</font>
	<font color=green>//        {</font>
	<font color=green>//            ksl::cout << x << ksl::endl;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      is valid, as x is interpreted as "mu& x" (by reference). Likewise,</font>
	<font color=green>//      we have the added advantage of having</font>
	<font color=green>//</font>
	<font color=green>//        function void print_stuff(const x)</font>
	<font color=green>//        {</font>
	<font color=green>//            ksl::cout << x << ksl::endl;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      being valid, because "const x" means "const mu& x". Nice one. NOTE: This </font>
	<font color=green>//      may or may not make the final cut (parsing ambiguities are possible).</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Default Parameters</font>
	<font color=green>//    --------------------</font>
	<font color=green>//      These work just like C++, although ambiguities can arise if the parameter</font>
	<font color=green>//      type is left out:</font>
	<font color=green>//</font>
	<font color=green>//        function void print_stuff(x = 4) // unsigned/signed, etc...</font>
	<font color=green>//        {</font>
	<font color=green>//            //...</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    muud( )</font>
	<font color=green>//    ---------</font>
	<font color=green>//      Langauge-feature: Returns true if the type of a variable is mu. </font>
	<font color=green>//      False if anything else. I suspect there'd be a lot of</font>
	<font color=green>//      "typeof(variable) != mu" otherwise.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  The Mue-Type</font>
	<font color=green>//  --------------</font>
	<font color=green>//    I struggled for a while with Mu, mainly because we may not want</font>
	<font color=green>//    to assign a type to mu via the assignment operator - we may want</font>
	<font color=green>//    to catch potential errors like this:</font>
	<font color=green>//</font>
	<font color=green>//      mu Age = uint(5);</font>
	<font color=green>//      Age = string("hey man!");</font>
	<font color=green>//      uint total_age = other_ages + Age;</font>
	<font color=green>//</font>
	<font color=green>//    To do so, I introduce Mue - "Mu-Explicit". This is identical to Mu,</font>
	<font color=green>//    with the exception that assignment of type doesn't work implicitly.</font>
	<font color=green>//    I actually suggest using Mue (still pronounced, like Mu, as "Moo"),</font>
	<font color=green>//    instead of Mu generally, because it is safer.</font>
	<font color=green>//</font>
	<font color=green>//    Obviously, you can not use Mue as a parameter in a function (allowing</font>
	<font color=green>//    that was the reason Mu had to have implicit assignment of type).</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>

		<font color=green>//=====================================================================</font>
		<font color=green>// Real World(tm) Examples</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// if two types are equal</font>
			<font color=blue>function</font> <font color=blue>boolean</font> sametype(<font color=blue>const</font> <font color=blue>mu</font>& lhs, <font color=blue>const</font> <font color=blue>mu</font>& rhs)
			{
				<font color=blue>return</font> <font color=blue>typeof</font>(lhs) == <font color=blue>typeof</font>(rhs);
			}
			
			<font color=green>// assumes dest and source are pointer-types. run-time failure if not.</font>
			<font color=blue>function</font> <font color=blue>void</font> copy_memory(<font color=blue>mu</font> dest, <font color=blue>mu</font> source, uint size)
			{
				<font color=blue>for_count</font>(size) *(dest++) = *(source++);
			}
			
			<font color=green>// swap value of two things of the same type, compile-timely</font>
			<font color=blue>function</font> <font color=blue>void</font> swap<<font color=blue>datatype</font> T>(T & lhs, T & rhs)
			{
				T temp(lhs);
				lhs = rhs;
				rhs = temp;
			}

			<font color=green>// swap value of two things of the same type, run-timely</font>
			<font color=blue>function</font> <font color=blue>void</font> swap(<font color=blue>mu</font> & lhs, <font color=blue>mu</font> & rhs) <font color=blue>where</font> (sametype(lhs, rhs))
			{
				<font color=blue>mu</font> temp = lhs;
				lhs = rhs;
				rhs = temp;
			}
		}
		
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Classes and Datatypes</font>
	<font color=green>//  -----------------------</font>
	<font color=green>//    There is no distinction between primitives and classes, each is</font>
	<font color=green>//    a "datatype". Thus there is no "class" keyword. "Classes" are very</font>
	<font color=green>//    similar to C++/Java. Datatypes take the form of:</font>
	<font color=green>//</font>
	<font color=green>//      datatype "name" [ < "datatype-list" > ] </font>
	<font color=green>//                      [ [ inherits "base-list" [ where ( "boolean-expression" ) ];</font>
	<font color=green>//                        | inherits "base-list" [ where ( "boolean-expression" ) ]</font>
	<font color=green>//        {</font>
	<font color=green>//            "member-list"</font>
	<font color=green>//        } ]</font>
	<font color=green>//</font>
	<font color=green>//    Declaration</font>
	<font color=green>//    -------------</font>
	<font color=green>//      You can have either the datatype inheriting from other datatypes,</font>
	<font color=green>//      or the definition (ie, { and } with the methods/members in between), </font>
	<font color=green>//      or both. Ie, all of these are legal:</font>
	<font color=green>//     </font>
	<font color=green>//        datatype height inherits real;</font>
	<font color=green>//</font>
	<font color=green>//        datatype Feline</font>
	<font color=green>//        {</font>
	<font color=green>//            public virtual function void Meow();</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//        datatype tabby_cat inherits Pet, Feline</font>
	<font color=green>//        {</font>
	<font color=green>//            public function void Meow();</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//    Validation</font>
	<font color=green>//    ------------</font>
	<font color=green>//      Dimensional analysis is provided by an expression that evaluates</font>
	<font color=green>//      to a boolean value, after "where". This is verified everytime a</font>
	<font color=green>//      non-const operation is performed.</font>
	<font color=green>//</font>
	<font color=green>//        datatype height inherits real where (height < 2.1);</font>
	<font color=green>//</font>
	<font color=green>//      As you can see, the ending semicolon is only required when paranthesis</font>
	<font color=green>//      are not used, as shown above. An involved datatype with analysis is:</font>
	<font color=green>//</font>
	<font color=green>//        datatype Human </font>
	<font color=green>//          where (mName.size() <= 15 && age < 150)</font>
	<font color=green>//        {</font>
	<font color=green>//            ksl::string mName;</font>
	<font color=green>//            uint mAge;</font>
	<font color=green>//        public:</font>
	<font color=green>//            const function ksl::string getName() { return mName; }</font>
	<font color=green>//            function void setName(ksl::string name) { mName = name; }</font>
	<font color=green>//            const function uint getAge() { return mAge; }</font>
	<font color=green>//            function void setAge(uint age) { mAge = age; }</font>
	<font color=green>//        public:</font>
	<font color=green>//            real<64> Height;</font>
	<font color=green>//            mu Eyes;</font>
	<font color=green>//        }</font>
	<font color=green>//      </font>
	<font color=green>//      In this example, the validation expression will be -after- execution of</font>
	<font color=green>//      setName and setAge, but NOT after getName and getAge, and they are const,</font>
	<font color=green>//      and such garuantee that nothing will change. Furthermore, any changes to</font>
	<font color=green>//      the public variable Height will NOT cause a re-evaluation, as the compiler</font>
	<font color=green>//      can easily check that Height isn't in the validation-expression, and as</font>
	<font color=green>//      such can not change the value of the other variables.</font>
	<font color=green>//</font>
	<font color=green>//      Changes to Eyes, however - will. This is because it is a mu-type variable,</font>
	<font color=green>//      and as such -could- take a datatype which changed the values of mName and</font>
	<font color=green>//      mAge, however bad that practice may be. I think this may be very inefficient,</font>
	<font color=green>//      so I may in the future introduce stricter limitations (somehow).</font>
	<font color=green>//</font>
	<font color=green>//      This simple validation could also be implemented by putting the restrictions</font>
	<font color=green>//      on the set functions, which would indeed speed up execution, as this way, </font>
	<font color=green>//      any modification to Eyes wouldn't require a re-evaluation (as there is no</font>
	<font color=green>//      datatype-validation in place).</font>
	<font color=green>//</font>
	<font color=green>//    Compile-Time Templating</font>
	<font color=green>//    -------------------------</font>
	<font color=green>//      Finally, compile-time types are supported through the very similar mechanism</font>
	<font color=green>//      to C++ templates. This allows for things like -speed-, which may be required</font>
	<font color=green>//      over flexibility. Such as the example of a replica of std::pair below:</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		
		<font color=green>//=====================================================================</font>
		<font color=green>// Real World Examples</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// compile-time pair</font>
			<font color=blue>datatype</font> pair <<font color=blue>datatype</font> T, <font color=blue>datatype</font> Y>
			{
			<font color=blue>public</font>:
				T First;
				Y Second;
				
				<font color=blue>function</font> pair(<font color=blue>const</font> T& f, <font color=blue>const</font> Y& s) : First(f), Second(s)
				{
				}
				
				<font color=blue>function</font> <font color=blue>void</font> swap() <font color=blue>where</font> ( <font color=blue>typeof</font>(T) == <font color=blue>typeof</font>(Y) )
				{
					ksl::swap(First, Second);
				}
			}

			<font color=green>// run-time pair</font>
			<font color=blue>datatype</font> pair
			{
			<font color=blue>public</font>:
				<font color=blue>mu</font><pair> First;
				<font color=blue>mu</font><pair> Second;

				<font color=blue>function</font> pair(<font color=blue>const</font> <font color=blue>mu</font>& f, <font color=blue>const</font> <font color=blue>mu</font>& s) <font color=blue>where</font> (<font color=blue>muud</font>(First) || <font color=blue>muud</font>(Second))
					: First(f), Second(s)
				{
				}

				<font color=blue>function</font> reassign(<font color=blue>const</font> <font color=blue>mu</font>& f, <font color=blue>const</font> <font color=blue>mu</font>& s)
				{
					First = f;
					Second = s;
				}
			}
		}
		
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Concepts</font>
	<font color=green>//  ----------</font>
	<font color=green>//    Concepts are very similar to what Bjourne is trying to introduce to </font>
	<font color=green>//    C++ in the next couple of decades. Concepts are not like interfaces - </font>
	<font color=green>//    you don't derive from them. They are similar to templated types in</font>
	<font color=green>//    C++, in that you just -assume- that the passed-in class has the</font>
	<font color=green>//    required methods/members. Those are then accessed directly.</font>
	<font color=green>//</font>
	<font color=green>//    This means you can pass in base classes (with pure virtual functions,</font>
	<font color=green>//    for example), and since the methods are called directly, it will</font>
	<font color=green>//    properly call the derived virtual functions. That is not shown here</font>
	<font color=green>//    today.</font>
	<font color=green>//</font>
	<font color=green>//    Definition</font>
	<font color=green>//    ------------</font>
	<font color=green>//      concept "name"</font>
	<font color=green>//      {</font>
	<font color=green>//          "member-list"</font>
	<font color=green>//      }</font>
	<font color=green>//</font>
	<font color=green>//    Example</font>
	<font color=green>//    ---------</font>
	<font color=green>//      concept Animal</font>
	<font color=green>//      {</font>
	<font color=green>//          const function integer getAge();</font>
	<font color=green>//          real<32> HappinessLevel;</font>
	<font color=green>//      }</font>
	<font color=green>//</font>
	<font color=green>//      datatype Duck</font>
	<font color=green>//      {</font>
	<font color=green>//      public:</font>
	<font color=green>//          const function integer getAge() { return 4; }</font>
	<font color=green>//          real<32> HappinessLevel;</font>
	<font color=green>//          private function void recogniseMate();</font>
	<font color=green>//      }</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    General Use</font>
	<font color=green>//    -------------</font>
	<font color=green>//      In general, we replace the "datatype" keyword in the compile-time</font>
	<font color=green>//      paramters with the concept name.</font>
	<font color=green>//</font>
	<font color=green>//        function void PrintAnimalAge<Animal A>(const A& animal)</font>
	<font color=green>//        {</font>
	<font color=green>//            ksl::cout << animal.getAge() << ksl::endl;</font>
	<font color=green>//        }</font>
	<font color=green>//    </font>
	<font color=green>//    Singular Use</font>
	<font color=green>//    --------------</font>
	<font color=green>//      We can compact the above function, but only because it does not</font>
	<font color=green>//      have the concept as the return type, and because it doesn't require</font>
	<font color=green>//      that two parameters be the same type. Like so:</font>
	<font color=green>//</font>
	<font color=green>//        function void PrintAnimalAge(const Animal& animal)</font>
	<font color=green>//        {</font>
	<font color=green>//            ksl::cout << animal.getAge() << ksl::endl;</font>
	<font color=green>//        }</font>
	<font color=green>//</font>
	<font color=green>//      Now, PrintAnimalAge will accept any type that "conforms" to the concept</font>
	<font color=green>//      of Animal - ie, it will accept Duck. You could imagine concepts as a</font>
	<font color=green>//      sort of more powerful type of mu - where it imposes rules on the methods</font>
	<font color=green>//      and members of a datatype (something mu can not express by itself).</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		
		<font color=green>//=====================================================================</font>
		<font color=green>// Real World Example</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// a concept that will enclose vectors, linkedlists, strings, etc</font>
			<font color=blue>concept</font> container
			{
				<font color=blue>concept</font> iterator;
				<font color=blue>concept</font> <font color=blue>const</font>_iterator;
				
				<font color=blue>function</font> iterator begin();
				<font color=blue>function</font> iterator end();
				<font color=blue>const</font> <font color=blue>function</font> <font color=blue>const</font>_iterator begin();
				<font color=blue>const</font> <font color=blue>function</font> <font color=blue>const</font>_iterator end();
			}

			<font color=green>// a non-const iterator over a container</font>
			<font color=blue>concept</font> container::iterator
			{
				<font color=green>// definitions...</font>
			}
			
			<font color=green>// a const iterator over a container</font>
			<font color=blue>concept</font> container::<font color=blue>const</font>_iterator
			{
				<font color=green>// definitions...</font>
			}
		}

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Expressions</font>
	<font color=green>//  -------------</font>
	<font color=green>//</font>
	<font color=green>//    expression [ "expression-name" ] [ < "datatype-list" > ] ( "parameters" ) </font>
	<font color=green>//               [ external ( "external-variables" ) ]</font>
	<font color=green>//               </font>
	<font color=green>//    {</font>
	<font color=green>//        "body"</font>
	<font color=green>//    }</font>
	<font color=green>//</font>
	<font color=green>//    Expressions are the method to allow for lambda functions, and for</font>
	<font color=green>//    a higher level of abstraction. This is allowed via the ability to</font>
	<font color=green>//    write anonymous expressions. Expressions effectively "replace" or </font>
	<font color=green>//    expand out to what is declared in the body, and allow for that sort </font>
	<font color=green>//    of thing to be declared within function parameters, like for_each, </font>
	<font color=green>//    sort and find_if.</font>
	<font color=green>//</font>
	<font color=green>//    Compile-Time Types</font>
	<font color=green>//    --------------------</font>
	<font color=green>//      Just like everything else, expressions can be templated. However,</font>
	<font color=green>//      since most useful features of expressions are their, "in place"</font>
	<font color=green>//      functionality, this generally won't (probably) be used.</font>
	<font color=green>//</font>
	<font color=green>//    External Variables</font>
	<font color=green>//    ---------------------</font>
	<font color=green>//      Expressions can modify variables in scope via declaring them external</font>
	<font color=green>//      to the expression. This is achieved via the "external" keyword.</font>
	<font color=green>//</font>
	<font color=green>//    Comparisons to C++</font>
	<font color=green>//    --------------------</font>
	<font color=green>//      The best case for expressions lies in comparisons to C++, most</font>
	<font color=green>//      notably in the std::for_each, std::find_if and std::sort uses,</font>
	<font color=green>//      which are generally used to show inabilities in C++ (in terms</font>
	<font color=green>//      of lambda functions).</font>
	<font color=green>//</font>
	<font color=green>//      To sort a vector of integers:</font>
	<font color=green>//        C++:</font>
	<font color=green>//          // look up std::less if you're unsure</font>
	<font color=green>//          sort(v.begin(), v.end(), std::less<int>());</font>
	<font color=green>//</font>
	<font color=green>//        Kaleidoscope:</font>
	<font color=green>//          // We'd assume this expression was part of the ksl</font>
	<font color=green>//          // Remember: No type is an implicit mu-type</font>
	<font color=green>//          expression less(A, B) { A < B; }</font>
	<font color=green>//          // and we'd use it like so:</font>
	<font color=green>//          sort(v.begin(), v.end(), less);</font>
	<font color=green>//</font>
	<font color=green>//      In this simple case, they are effectively the same, albeit shorter</font>
	<font color=green>//      in Kaleidoscope's case (as std::less is actually a struct). However,</font>
	<font color=green>//      this is a trivial example. Let us "upgrade".</font>
	<font color=green>//</font>
	<font color=green>//      This time, we want to sort a linked-list of meshes. Unfortunately,</font>
	<font color=green>//      The mesh datatype doesn't have a less-than operator. So normally under</font>
	<font color=green>//      C++ we'd have to write either our own boolean predicate and pass that</font>
	<font color=green>//      into std::sort, or write an explicit instance of std::less for the </font>
	<font color=green>//      datatype mesh. Either way it's a struct - not fun.</font>
	<font color=green>//</font>
	<font color=green>//      With expressions in Kaleidoscope, however, we can write it as an anonymous</font>
	<font color=green>//      expression:</font>
	<font color=green>//</font>
	<font color=green>//      sort(v.begin(), v.end(), expression (lhs, rhs) { lhs.size() < rhs.size(); } );</font>
	<font color=green>//</font>
	<font color=green>//    As you're aware now, expressions don't have to work with types, and</font>
	<font color=green>//    anonymous expressions generally won't.</font>
	<font color=green>//</font>
	<font color=green>//    </font>
	<font color=green>//</font>
	<font color=green>//    The "external" keyword is there to allow the expressions to access</font>
	<font color=green>//    variables within its enclosing scope. This allows for the functionality</font>
	<font color=green>//    that is -just- out of for_each's grasp:</font>
	<font color=green>//</font>
	<font color=green>//      int total = 0;</font>
	<font color=green>//      for_each(numbers, expression (x) external(total) { total += x; } );</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		
		<font color=green>//=====================================================================</font>
		<font color=green>// Real World Examples</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// multi-purpose less-than expression</font>
			<font color=blue>expression</font> less_than(<font color=blue>const</font> A, <font color=blue>const</font> B)
			{
				A < B;
			}
			
			<font color=green>// multi-purpose greater-than expression</font>
			<font color=blue>expression</font> greater_than(<font color=blue>const</font> A, <font color=blue>const</font> B)
			{
				A > B;
			}
		}

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Jars</font>
	<font color=green>//  ------</font>
	<font color=green>//    The idea of the jar is pretty simple really - it's where we keep</font>
	<font color=green>//    stuff. Namely, it's where we keep datatypes, expressions and </font>
	<font color=green>//    functions. We do it because if we didn't have the "_jar" postfix,</font>
	<font color=green>//    the compiler would be unable to tell if we weren't forward</font>
	<font color=green>//    declaring a datatype or whatnot.</font>
	<font color=green>//</font>
	<font color=green>//    The jars (their formal definitions) are:</font>
	<font color=green>//</font>
	<font color=green>//      - datatype_jar "variable-name" ;</font>
	<font color=green>//      - expression_jar "variable-name" ;</font>
	<font color=green>//      - function_jar "variable-name" ;</font>
	<font color=green>//</font>
	<font color=green>//    datatype_jar + expression_jar</font>
	<font color=green>//    -------------------------------</font>
	<font color=green>//      These two jars act identically, except with their respective fields,</font>
	<font color=green>//      of course. They are the jars that hold which datatype something is,</font>
	<font color=green>//      or which expression (yet to be covered) is. For example:</font>
	<font color=green>//</font>
	<font color=green>//        datatype_jar j = typeof(string);</font>
	<font color=green>//</font>
	<font color=green>//      j now equals the type of string. We can use this to type mu-types,</font>
	<font color=green>//      such as this example:</font>
	<font color=green>//</font>
	<font color=green>//        mu x;</font>
	<font color=green>//        datatype_jar j = typeof(string);</font>
	<font color=green>//        x<j> = "Totally valid!";</font>
	<font color=green>//        j = int;</font>
	<font color=green>//        x<j> = 5; // more totally valid!</font>
	<font color=green>//</font>
	<font color=green>//      I do not think this concept requires any additional explanation, save</font>
	<font color=green>//      the reassurance that you can pass jars around as parameters.</font>
	<font color=green>//</font>
	<font color=green>//    function_jar</font>
	<font color=green>//    --------------</font>
	<font color=green>//      This is the equivalent of a function pointer, and as such function</font>
	<font color=green>//      pointers do not exist in Kaleidoscope. It has the syntax of:</font>
	<font color=green>//</font>
	<font color=green>//        function_jar "variable-name" [ < "variable-name" > ] ;</font>
	<font color=green>//</font>
	<font color=green>//      Non-member functions</font>
	<font color=green>//      ----------------------</font>
	<font color=green>//        They are simply assigned, like so:</font>
	<font color=green>//</font>
	<font color=green>//          function void print(integer x) { ksl::cout << x << ksl::endl; }</font>
	<font color=green>//          function_jar f = print;</font>
	<font color=green>//          f(5); // calls the function</font>
	<font color=green>//</font>
	<font color=green>//        As you can see, the concept of pointers in function pointers has</font>
	<font color=green>//        been completely eliminated. Instead, we have a jar in which you</font>
	<font color=green>//        can put functions.</font>
	<font color=green>//</font>
	<font color=green>//      Member functions</font>
	<font color=green>//      ------------------</font>
	<font color=green>//        The syntax for these is wonderfully easy. As you're aware, if you</font>
	<font color=green>//        read the syntax above, there's an optional datatype you can apply</font>
	<font color=green>//        to the function_jar, in between triangle brackets. This is defaultly</font>
	<font color=green>//        mu, and for good reason. If it is mu, the function_jar is expecting</font>
	<font color=green>//        a non-member function.</font>
	<font color=green>//</font>
	<font color=green>//        However, it can be changed to the type of datatype you're trying to</font>
	<font color=green>//        store. The instance of that datatype is passed in like below:</font>
	<font color=green>//</font>
	<font color=green>//          datatype Cat { public integer getAge(integer x) { return x * 7; } }</font>
	<font color=green>//          Cat my_cat;</font>
	<font color=green>//          function_jar f<Cat> = <my_cat>::getAge();</font>
	<font color=green>//          f(6); // returns 42 (haha, that was a coincidence)</font>
	<font color=green>//</font>
	<font color=green>//        As you can see, the idea behind this decision was to show that the</font>
	<font color=green>//        two things in the triangle brackets should match up. If you want to</font>
	<font color=green>//        back to non-member functions, simply:</font>
	<font color=green>//</font>
	<font color=green>//          f<mu>;</font>
	<font color=green>//</font>
	<font color=green>//        will do. The value of f at this point is undefined. (Possibly extensions</font>
	<font color=green>//        include allowing virtual functions to polymorph appropriately if the</font>
	<font color=green>//        type change was between two polymorphic types... tricky).</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	
		<font color=green>//=====================================================================</font>
		<font color=green>// Real World Examples</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=green>// like std::for_each</font>
			<font color=blue>function</font> <font color=blue>void</font> for_each(container& c, <font color=blue>expression</font>_jar expr)
			{
				<font color=blue>for</font> (container::iterator i = c.begin(); i != c.end(); ++i)
				{
					expr(*i);
				}
			}
			
			<font color=green>// like std::find_if</font>
			<font color=blue>function</font> C::<font color=blue>const</font>_iterator find_if<container C>(<font color=blue>const</font> C& c, <font color=blue>expression</font>_jar expr)
			{
				<font color=blue>for</font> (C::<font color=blue>const</font>_iterator i = c.begin(); i != c.end(); ++i)
				{
					<font color=blue>if</font> (expr(*i)) <font color=blue>return</font> i;
				}
				<font color=blue>return</font> c.end();
			}

			<font color=green>// performs a crappy bubble sort</font>
			<font color=blue>function</font> <font color=blue>void</font> sort(container& c, <font color=blue>expression</font> E = less_than)
			{
				<font color=blue>for_count</font> (c.size() - 1)
				{
					<font color=blue>for</font> (<font color=blue>autotype</font> i = c.begin(), <font color=blue>autotype</font> j = c.next(i); j != c.end(); ++i, ++j)
					{
						<font color=blue>if</font> ( E(*i, *j) ) ksl::swap(i, j);
					}
				}
			}
		}

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Inheritance, Polymorphism, and "Monomorphism"</font>
	<font color=green>//  ---------------------------------------------</font>
	<font color=green>//    I struggled for a while about how to succinctly define the whole</font>
	<font color=green>//    type hierarchy thing whilst allowing for inheritance and</font>
	<font color=green>//    polymorphism. A good example is:</font>
	<font color=green>//</font>
	<font color=green>//      datatype height inherits real where (height < 2.1 && height >= 0);</font>
	<font color=green>//</font>
	<font color=green>//    Now, while real is a superset of "height" (which has limitiations), </font>
	<font color=green>//    "height" is not technically -inheriting- so much as it IS height,</font>
	<font color=green>//    but with the addition of the limitations.</font>
	<font color=green>//</font>
	<font color=green>//    Traditional polymorphism occurs via pointers - what I term</font>
	<font color=green>//    "monopmorphism" does not (per se the language). Such that if you</font>
	<font color=green>//    had a class D that derived from B (for example, CTextureDX derives</font>
	<font color=green>//    from ITexture) - polymorphism works as normal:</font>
	<font color=green>//</font>
	<font color=green>//      - dynamic_cast< > works like C++</font>
	<font color=green>//      - static_cast< > works like C++</font>
	<font color=green>//</font>
	<font color=green>//    However, for situations like the "height" example, "monomorphism"</font>
	<font color=green>//    is possible:</font>
	<font color=green>//</font>
	<font color=green>//      real r = height(1.23)</font>
	<font color=green>//</font>
	<font color=green>//    It is termed "monomorphism" (and I use it in quotation marks because</font>
	<font color=green>//    it's probably called something else) - because it is not possible</font>
	<font color=green>//    with multiple inheritance, and neither is it possible if the "derived"</font>
	<font color=green>//    class defines any members at all. All that is allowed is dimensional</font>
	<font color=green>//    analysis. Thus the above definition of "height" is valid.</font>
	<font color=green>//</font>
	<font color=green>//    Effectively, there's no morphing at all - the assignment operators</font>
	<font color=green>//    can be generated at compile time by the compiler. Note that an</font>
	<font color=green>//    inherited type will inherit all the dimensional analysis rules its</font>
	<font color=green>//    parent has. So:</font>
	<font color=green>//</font>
	<font color=green>//      datatype dwarf_height inherits height where (dwarf_height > 2.1);</font>
	<font color=green>//</font>
	<font color=green>//    would be invalid - although I'm pretty sure for all cases this is an</font>
	<font color=green>//    undecidable problem. The compiler should/would be able to catch 95%</font>
	<font color=green>//    of the mismatches, though.</font>
	<font color=green>//</font>
	<font color=green>//    This area needs to most suggestions, guys.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Pointers & Garbage Collection</font>
	<font color=green>//  -------------------------------</font>
	<font color=green>//    GC is good, but for writing games, it isn't -that- good. Especially</font>
	<font color=green>//    Java's model for it (big sweeps every second or so). However, there</font>
	<font color=green>//    is definately a need for it, but it should be at the user's</font>
	<font color=green>//    discretion. In the form presented, there is no "default" - it all</font>
	<font color=green>//    depends upon the user/</font>
	<font color=green>//</font>
	<font color=green>//    Regular Ol' Pointers</font>
	<font color=green>//    ----------------------</font>
	<font color=green>//      As per normal in C/C++.</font>
	<font color=green>//</font>
	<font color=green>//        int * i = new int(53);</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    Memory Managed Pointers ("Smart Pointers")</font>
	<font color=green>//    --------------------------------------------</font>
	<font color=green>//      Pinched from C#/Managed C++:</font>
	<font color=green>//</font>
	<font color=green>//        int ^ i = new int(53):</font>
	<font color=green>//</font>
	<font color=green>//      There are some differences, however. Smart Pointers are garuanteed</font>
	<font color=green>//      to be initilaised to NULL. Furthermore, Smart Pointers are effectively</font>
	<font color=green>//      like boost::shared_ptrs, -except- they have the ability to avoid</font>
	<font color=green>//      this nasty problem:</font>
	<font color=green>//</font>
	<font color=green>//        int ^ i = new int(53);</font>
	<font color=green>//        int * j = raw_pointer_cast(i);</font>
	<font color=green>//        int ^ k = raw_pointer_cast(j);</font>
	<font color=green>//</font>
	<font color=green>//      In that situation, the memory pointed to by both i and k will</font>
	<font color=green>//      have the "reference" at "two", and not "one" (this is the required</font>
	<font color=green>//      behaviour - implementation doesn't matter).</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    raw_pointer_cast( )</font>
	<font color=green>//    ---------------------</font>
	<font color=green>//      As used above, a raw_pointer_cast converts from a Smart</font>
	<font color=green>//      Pointer to a Raw Pointer, and back again. They can not do that</font>
	<font color=green>//      implicitly, as programmers really need to be aware when they're</font>
	<font color=green>//      doing dangerous stuff like that.</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//    release( )</font>
	<font color=green>//    ------------</font>
	<font color=green>//      Smart Pointers have the language-feature of having a function</font>
	<font color=green>//      "release", allowing them to release their data and becomming</font>
	<font color=green>//      NULL again:</font>
	<font color=green>//</font>
	<font color=green>//        int ^ i; // equals NULL</font>
	<font color=green>//        i = new int(53);</font>
	<font color=green>//        i.release(); // back to NULL</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		
		<font color=green>//=====================================================================</font>
		<font color=green>// Real World Examples</font>
		<font color=green>//  - Note: I'm not happy with the syntax for const references to</font>
		<font color=green>//          smart pointers - but I can't think of another way.</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>datatype</font> Mesh
		{
			VertexBuffer ^ mVertexBuffer;
			IndexBuffer ^ mIndexBuffer;
			ksl::string mName;
			
		<font color=blue>public</font>:
			<font color=blue>function</font> Mesh(<font color=blue>const</font> ksl::string& name) : mName
			{
			}

			<font color=blue>function</font> <font color=blue>void</font> setVertexBuffer(<font color=blue>const</font> VertexBuffer^& vb)
			{
				mVertexBuffer = vb;
			}

			<font color=blue>function</font> <font color=blue>const</font> VertexBuffer^& getVertexBuffer()
			{
				<font color=blue>return</font> mVertexBuffer;
			}
		}
			

	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//  Classes Revisited</font>
	<font color=green>//  -------------------</font>
	<font color=green>//    This simple (and not-safe) implementation of the std::vector</font>
	<font color=green>//    class is to demonstrate some advanced forms of typing, only briefed</font>
	<font color=green>//    over before.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
		<font color=blue>namespace</font> ksl
		{
			<font color=blue>datatype</font> vector
			{
			<font color=blue>private</font>:
				<font color=blue>mu</font>e _begin;
				<font color=blue>mu</font>e _end;
				<font color=blue>mu</font>e _cur;
				
				<font color=green>// type we're working with atm - initially set to mu</font>
				<font color=blue>datatype</font>_jar _T;
				
			<font color=blue>public</font>:
				<font color=green>//=====================================================================</font>
				<font color=green>// Default Constructor</font>
				<font color=green>// ---------------------</font>
				<font color=green>//  We do nothing - not even initialising the mu-types.</font>
				<font color=green>//=====================================================================</font>
				vector()
				{
				}
				
				<font color=green>//=====================================================================</font>
				<font color=green>// Mue-type Initialisation</font>
				<font color=green>// ----------------------------</font>
				<font color=green>//   Note we need to explicitly define the mue-type variables, and since</font>
				<font color=green>//   that takes higher precedence than the constructor, everything works</font>
				<font color=green>//   nicely.</font>
				<font color=green>//=====================================================================</font>
				vector(uint<32> size, <font color=blue>datatype</font>_jar T)
					: _T(T), 
					  _begin<T*>(new T[size]), _end<T*>(_begin + size), _cur<T*>(_begin), _T(T)
				{
				}
				
				<font color=green>// Simpler version</font>
				vector(<font color=blue>datatype</font>_jar T)
					: _T(T), 
					  _begin<T*>(NULL), _end<T*>(NULL), _cur<T*>(NULL),
				{
				}
				
				<font color=green>// Destructor - as per normal</font>
				~vector()
				{
					delete [] _begin;
				}
				
				<font color=green>//=====================================================================</font>
				<font color=green>// The following functions work properly because pointer arithmatic</font>
				<font color=green>// is defined, due to _begin, _end and _cur having definitive types.</font>
				<font color=green>//=====================================================================</font>
				<font color=blue>inline</font> <font color=blue>function</font> <font color=blue>const</font> _T& operator [](uint<32> index) <font color=blue>const</font>
				{
					<font color=blue>return</font> *(_begin + index);
				}
				
				<font color=blue>inline</font> <font color=blue>function</font> _T& operator [](uint index)
				{
					<font color=blue>return</font> *(_begin + index);
				}
				
				<font color=blue>inline</font> <font color=blue>function</font> uint<64> size() <font color=blue>const</font>
				{
					<font color=blue>return</font> _end - _begin;
				}
				
				<font color=blue>inline</font> <font color=blue>function</font> <font color=blue>void</font> clear()
				{
					delete [] _begin;
					_begin = _end = _cur = NULL;
				}
				
				<font color=green>// allow assignment to wipe our previous types (although make sure we</font>
				<font color=green>// delete the held data, if any</font>
				<font color=blue>inline</font> <font color=blue>function</font> <font color=blue>const</font> vector& operator = (<font color=blue>const</font> vector& v)
				{
					<font color=blue>if</font> (!<font color=blue>muud</font>(_T) && _begin) delete [] _begin;
					
					<font color=green>// change over type</font>
					_T<v._T>;
					
					<font color=green>// we managed to get all three brackets on the next line</font>
					_begin<_T>(new T[v.size()]); 
					_end<_T>(_begin + v.size());
					_cur<_T>(_begin + (v._cur - v._begin));
					
					<font color=blue>return</font> *this;
				}
						
				<font color=green>//=====================================================================</font>
				<font color=green>// if we'd used the default constructor, then _T would have</font>
				<font color=green>// been mu-type, meaning any datatype could be passed in as a value.</font>
				<font color=green>// It also means that _T will NOT have been changed, because it is</font>
				<font color=green>// not a mu-type, but rather it is a datatype_jar. Therefore we can</font>
				<font color=green>// use it for comparison. We should initialise things then to the</font>
				<font color=green>// type just presented.</font>
				<font color=green>//=====================================================================			</font>
				<font color=blue>function</font> <font color=blue>const</font> _T& push_back(<font color=blue>const</font> _T& value)
				{
					<font color=blue>if</font> (<font color=blue>muud</font>(_T))
					{
						*this = vector(<font color=blue>typeof</font>(value));
					}
					
					<font color=green>// I actually have no idea if this algorithm correctly</font>
					<font color=green>// pads a vector. kind of fun to write though.</font>
					<font color=blue>if</font> (_cur == _end)
					{
						
						clone_<font color=blue>datatype</font><_begin> temp = _begin;
						
						uint<64> old_size = _end - _begin;
						uint<64> new_size = old_size * 1.5 + 1;
						
						_begin = new T[new_size];
						
						<font color=green>// just like memcpy</font>
						copy_memory(_begin, temp, old_size);
						
						_cur = begin + old_size;
						_end = _begin + new_size;
					}
					
					*(_cur++) = value;
				}
			}
	
		
	<font color=green>//=====================================================================</font>
	<font color=green>//</font>
	<font color=green>//                  D E M O N S T R A T I O N</font>
	<font color=green>//                    -------------------------</font>
	<font color=green>//                             Yay!</font>
	<font color=green>//</font>
	<font color=green>//</font>
	<font color=green>//  A Short Demonstration On Usage</font>
	<font color=green>//  --------------------------------</font>
	<font color=green>//    This is a simple demonstration of how the above-written classes,</font>
	<font color=green>//    functions, expressions, etc, could mesh together. It is pretty</font>
	<font color=green>//    simple - we are simply making a vector of numbers, sorting them,</font>
	<font color=green>//    and then displaying them.</font>
	<font color=green>//</font>
	<font color=green>//=====================================================================</font>
	
		<font color=green>//=====================================================================</font>
		<font color=green>// Displays a given thing</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>expression</font> display(t)
		{
			ksl::cout << t << ksl::endl;
		}
		
		<font color=green>//=====================================================================</font>
		<font color=green>// The Main Function</font>
		<font color=green>// -------------------</font>
		<font color=green>//   From here on out, no more long descriptions, just example code</font>
		<font color=green>//=====================================================================</font>
		<font color=blue>function</font> int main()
		{
			ksl::vector v(<font color=blue>integer</font>);
			v.push_back(75);
			v.push_back(2);
			v.push_back(-634);
			v.push_back(231);
			v.push_back(15);
			v.push_back(18);
			v.push_back(-77);
			v.push_back(400);
			
			<font color=green>// would cause a run-time fail, because v::mT is not const char *,</font>
			<font color=green>// (see ksl::vector::push_back)</font>
			<font color=green>// -------------------------------------</font>
			<font color=green>//    v.push_back("bork bork!");</font>
			
			<font color=green>// display the undordered vector</font>
			ksl::for_each(v, display);
			<font color=green>// sort - ksl::sort takes ksl::less_than as default</font>
			ksl::sort(v);
			<font color=green>// display the ordered vector, this time with an anonymous expression</font>
			ksl::for_each(v, <font color=blue>expression</font> (x) { ksl::cout << "E: " << x << ksl::endl; } );
			
			<font color=green>// sort by greater than</font>
			ksl::sort(v, <font color=blue>expression</font>(A, B) { A > B; } );
			<font color=green>// display newly ordered vector</font>
			ksl::for_each(v, display);
			
			<font color=green>// find the position 231 is in</font>
			<font color=blue>autotype</font> pos = find_if(v, <font color=blue>expression</font> (A) { A == 231 });
			<font color=green>// display it - assuming vector::iterator had an "index()" method, which is really wouldn't.</font>
			ksl::cout << "Position of 231: " << pos.index() << ksl::endl;
		}

ApochPiQ
ApochPiQ
Here's my thoughts, just reading through the doc:

  • Why can I only have unsigned integers but not unsigned reals? IMHO this is a consistency issue; either signedness should be fully part of a type constraints mechanism, or any numeric primitive should have access to it. For the sake of cleanliness, I personally prefer the former.

  • The C/C++ typedef syntax is ugly; I'd really like to see someone think up a better one. Off the top of my head, even something subtle like alias (unsigned integer) as (uint); would be nice. That's largely subjective, though; but I guess the underlying question is, how close do you really want to stay to C/C++ syntax?

  • What exactly do you intend autotype to accomplish? You are aware that the C++ auto has absolutely nothing to do with types, right? (It is purely a scoping semantic, and is implicit in all variable declarations unless superseded by another explicit semantic keyword.) Skipping a head a bit, it looks like you intend autotype to be an inferred type placeholder, similar to C#'s var.

  • Why introduce yet another loop syntax? C/C++ for syntax is a little kludgy anyways. If you're going to go to all the trouble to confusing people who have a C/C++ background, at least do the job right and come up with a new syntax that doesn't have all of C/C++'s ugly problems [wink]

  • muud is a funny little pun. Puns have absolutely no place in a language's keyword set. Favor being actually expressive, and use ismu or is_mu - as a bonus, the IsFoo idiom is familiar from many other languages that have special first-class sentinel values (e.g. null, Nothing, etc.)

  • Why do you need permission specifiers on namespaces? Maybe you should use a class with static members? (Assuming you stay close to the C++ OO paradigm, which I'm guessing you do.) Also, namespaces should never need a "protected" specifier in any case - inheriting from namespaces is a bogus notion. If you need inheritance, use a class, not an identifier grouping mechanism.

  • static functions probably aren't needed unless you're planning on duplicating C++'s incredibly stupid compilation model. For the sake of the 21st century, I'd highly recommend removing C++'s internal/external linkage crap and use an access-specifier system exclusively, or something. Actually, this kind of goes for inline as well... or maybe not. Depends a lot on your compilation model really.

  • Your template syntax looks like it's going to create one hell of a messy grammar [wink]

  • Your validation syntax is fine if you have really trivial validation. However, if you need complex logic for validation (not uncommon in major systems!) or any long expressions, that syntax may be a bit limiting. I'd personally suggest having a function syntax like thus:
    function foo()
    {
    main_body_statements;
    }
    preconditions
    {
    // logic here; this is basically an anonymous boolean function
    }
    postconditions
    {
    // same as precon, just evaluated after the function return()s
    }

    Personally I'd like to see validation support done really first class - deeply supported and not feeling tacked onto the end of my function headers. That's just me, though.

  • Your mu concept seems like some fancy hand-waving to disguise a vanilla variant concept. Maybe you should just call it a variant so most people will recognize what you're talking about [wink]

  • Your smart-pointer syntax makes me sad: it means I have even less chance of seeing the ^^ logical XOR operator, which I wish for on a regular basis in C++.

  • Why do you want a push_back of an invalid type to fail at run time? Shouldn't that be failing at compile time, where it is already obvious that we're doing something stupid (pushing a string onto a vector of integers)?



The rest of the stuff is largely just my own subjective distaste for some of your decisions, so it's basically irrelevant [smile]

Personally, I think this is too much like trying to band-aid C++, but that's just the sense I get. IMHO this is just a recipe for yet more inconsistency, inelegance, and weird corner cases to pile on top of C++'s already rich trove of that kind of stuff.


_goat
_goat
Quote:
Original post by ApochPiQ
Here's my thoughts, just reading through the doc:

  • Why can I only have unsigned integers but not unsigned reals? IMHO this is a consistency issue; either signedness should be fully part of a type constraints mechanism, or any numeric primitive should have access to it. For the sake of cleanliness, I personally prefer the former.


I don't know. I can't see a problem with unsigned real numbers (and the higher-level concept of a number). I haven't got the foggiest idea how you could implement the signed keyword for generic datatypes though, nor what purpose it would serve.

Quote:
  • The C/C++ typedef syntax is ugly; I'd really like to see someone think up a better one. Off the top of my head, even something subtle like alias (unsigned integer) as (uint); would be nice. That's largely subjective, though; but I guess the underlying question is, how close do you really want to stay to C/C++ syntax?


  • I'm not really concerned with how closely we stick to the C++ syntax in general. This project grew out of C++, and thus it retains many of its stylistic things. This point seems a little trivial though.

    Quote:
  • What exactly do you intend autotype to accomplish? You are aware that the C++ auto has absolutely nothing to do with types, right? (It is purely a scoping semantic, and is implicit in all variable declarations unless superseded by another explicit semantic keyword.) Skipping a head a bit, it looks like you intend autotype to be an inferred type placeholder, similar to C#'s var.


  • I had actually thought to term it "inferredtype", but that seemed to difficult to write, and I thought people would be abreast with Bjourne's ideas on changing the auto keyword in C++ (he has a paper somewhere, I cbf finding it right now, it's 3:30AM over here). I don't see a problem with renaming it, it's just an arbitary word chosen to represent a concept.

    Quote:

  • Why introduce yet another loop syntax? C/C++ for syntax is a little kludgy anyways. If you're going to go to all the trouble to confusing people who have a C/C++ background, at least do the job right and come up with a new syntax that doesn't have all of C/C++'s ugly problems [wink]


  • I guess so? This seems a little nit-picky, seeing as it really isn't anything important to the structure of the language. It really just comes down to whether or not a feature is deemed worth it's while, since the amount people can hold in their head is finite.

    Quote:
  • muud is a funny little pun. Puns have absolutely no place in a language's keyword set. Favor being actually expressive, and use ismu or is_mu - as a bonus, the IsFoo idiom is familiar from many other languages that have special first-class sentinel values (e.g. null, Nothing, etc.)


  • Ha, actually, muud comes from my own mode of speech, where I tack on the "-ed" postfix to create verbs out of nouns. There was one point on these forums where I wrote up someone's C-with-classes code into proper C++, and told them they were Zahlmanned. However, I agree with the is_mu/ismu proposition, mainly because, yes, it is familiar with more people. Although I don't think anyone would have trouble with muud. Also, what the hell is the pun? I don't get it [sad].

    Quote:

  • Why do you need permission specifiers on namespaces? Maybe you should use a class with static members? (Assuming you stay close to the C++ OO paradigm, which I'm guessing you do.) Also, namespaces should never need a "protected" specifier in any case - inheriting from namespaces is a bogus notion. If you need inheritance, use a class, not an identifier grouping mechanism.

  • static functions probably aren't needed unless you're planning on duplicating C++'s incredibly stupid compilation model. For the sake of the 21st century, I'd highly recommend removing C++'s internal/external linkage crap and use an access-specifier system exclusively, or something. Actually, this kind of goes for inline as well... or maybe not. Depends a lot on your compilation model really.


  • These problems are directly related to me not thinking about the compilation model at all. I completely missed that having static functions would tie this language into a C++ style compilation model, which I too hate. Damn precious time. The point about the namespaces actually came from one of your posts, except it pertained to Java-style modules. Namespaces probably aren't the right choice of word to express the intention I mean. Module is perhaps the better choice.

    Quote:
  • Your template syntax looks like it's going to create one hell of a messy grammar [wink]


  • You don't have to use it if you don't want to. And like Lisp is any better [grin].

    Quote:
  • Your validation syntax is fine if you have really trivial validation. However, if you need complex logic for validation (not uncommon in major systems!) or any long expressions, that syntax may be a bit limiting. I'd personally suggest having a function syntax like thus:
    function foo()
    {
    main_body_statements;
    }
    preconditions
    {
    // logic here; this is basically an anonymous boolean function
    }
    postconditions
    {
    // same as precon, just evaluated after the function return()s
    }

    Personally I'd like to see validation support done really first class - deeply supported and not feeling tacked onto the end of my function headers. That's just me, though.


  • I understand what you mean, and I looked at it, but I couldn't in good consience make validation a first-class citizen in the language, as it would seriously mess up not only the grammars of the language, but also the syntax. I'm quite happy to extend the validation to pre and post conditions however, although I wouldn't give them the parenthesis, but probably just the brackets to evaluate the a boolean expression (but that's just to fit into the philosophy of what each bracket-type does).

    Quote:
  • Your mu concept seems like some fancy hand-waving to disguise a vanilla variant concept. Maybe you should just call it a variant so most people will recognize what you're talking about [wink]


  • Like I said, I have no formal language study under my belt, and an only limited amount of exposure to other languages (from C++/Java). That being said, I prefer mu (and mue) over variant, essentially because it can define a type of variable and the state of a dynamic variable, which variant can't (ie, a variant can never have the type "variant").

    Quote:
  • Your smart-pointer syntax makes me sad: it means I have even less chance of seeing the ^^ logical XOR operator, which I wish for on a regular basis in C++.


  • Um? I'm sure the language would have an XOR operator, possibly called "xor". But yes, I would go for pointer consitancy than trying to get laughing eyes for xor-operator.

    Quote:
  • Why do you want a push_back of an invalid type to fail at run time? Shouldn't that be failing at compile time, where it is already obvious that we're doing something stupid (pushing a string onto a vector of integers)?


  • This is purely a design issue in the example code - the vector is designed that way, so that's how it operates. However, you assume that it's a list that takes integers, when perhaps it's a list that takes strings but the first six or so entries were incorrect. It is a list that has a dynamic type. You can create a traditional list take a parameter template-style and doing compilation checking if you want. I gave examples of that for ksl::swap.

    Finally,

    Quote:
    Personally, I think this is too much like trying to band-aid C++, but that's just the sense I get. IMHO this is just a recipe for yet more inconsistency, inelegance, and weird corner cases to pile on top of C++'s already rich trove of that kind of stuff.


    I tend to agree with your sentiment, however, I disagree that this is a bad thing. C++ is widely used, not only because of the library support, but because can pull off powerful things in it, and if they know their STL well enough, can do it reasonably quickly (RAD langauges beat it hands down in GUIs of course). However, I think everyone has gotten knee-jerk reactionary on C++, especially the "language elite", that they view anything similar to C++ to of course having all the problems associated with it. I've already said I wouldn't mind (in fact, want) to change the compilation model, which throws a lot of those comparisons out the window.

    To this end, I would consider this a first step to "refactoring" C++ with a dynamic bent on it. And because it's a new language, and not an extension (as C++ was to C), we can certainly iron out all the little eccentricities that C++ has, and possibly create something far more cohesive.

    I've been (sort of) working on a second draft, which changes a few things, and introduces some things I haven't already covered. I'll certainly take your points into consideration.
    ZQJ
    ZQJ
    I have to admit I haven't read through all that thoroughly, but a couple of things (particularly since I haven't posted in ages and want to show I'm still here):

    Type system: I don't know if you intended something like the following to be part of your type system or not since it doesn't seem to be mentioned. Anyway, for example:

    class Vector(type Scalar){  Vector operator + (Vector A, Vector B);  Vector operator - (Vector A, Vector B);  Scalar operator * (Vector A, Vector B);  Vector operator * (Vector A, Scalar B);  Vector operator * (Scalar A, Vector B);};


    This is different from C++ inheritance because the Vector parameters must be of the same type, so it is more similar to C++ templates but involves better type restrictions on functions. I'm phrasing this badly. Anyway I'm sure somebody knows what I mean.

    The second thing is function contracts/preconditions/whatever. Exactly where do people think we should go with this? I've been looking into provability over the last few days and it seems surprisingly hard to prove some relatively simple things work as advertised. Maybe it's because I'm a bit of an amateur at this.

    On the compilation front I have to say I still support a gcc frontend. I don't think making a gcc frontend is particularly straightforward but it does buy a good amount of optimizing power and is probably easier than doing a compiler from scratch.
    _goat
    _goat
    Quote:
    Original post by ZQJ
    I have to admit I haven't read through all that thoroughly, but a couple of things (particularly since I haven't posted in ages and want to show I'm still here):

    Type system: I don't know if you intended something like the following to be part of your type system or not since it doesn't seem to be mentioned. Anyway, for example:

    class Vector(type Scalar){  Vector operator + (Vector A, Vector B);  Vector operator - (Vector A, Vector B);  Scalar operator * (Vector A, Vector B);  Vector operator * (Vector A, Scalar B);  Vector operator * (Scalar A, Vector B);};


    This is different from C++ inheritance because the Vector parameters must be of the same type, so it is more similar to C++ templates but involves better type restrictions on functions. I'm phrasing this badly. Anyway I'm sure somebody knows what I mean.


    I think what you're getting at is similar to the idea of concepts, such as:
    concept Vector{    // ...}concept Scalar{}V operator * <Vector V, Scalar S>(const V& lhs, const S& rhs);V operator * <Vector V, Scalar S>(const S& lhs, const V& rhs);


    Although using the * operator for the dot-product is bad mojo. In this way you can say "only Vector types (note that Vector is not actually a datatype, but just the concpet of one) can be used in this function, along with Scalar types".

    Quote:
    The second thing is function contracts/preconditions/whatever. Exactly where do people think we should go with this? I've been looking into provability over the last few days and it seems surprisingly hard to prove some relatively simple things work as advertised. Maybe it's because I'm a bit of an amateur at this.


    No, many things are unprovable - however, with the aforementioned structure, we actually have to write the code that will evaluate to a boolean expression. We're not writing abstract concepts, such as "function should make sure that pointer P is initialised to a correct memory address" - which is tricky to tell (although possible if you really wanted to hamstring your programming language). No, we'd be doing (P != NULL), and just hoping that they don't pass in an unitialised pointer, pointing to crap.

    Quote:
    On the compilation front I have to say I still support a gcc frontend. I don't think making a gcc frontend is particularly straightforward but it does buy a good amount of optimizing power and is probably easier than doing a compiler from scratch.


    I actually have no idea what you're talking about. A G++ frontend? What's the frontend of a compiler? Wait, no, I just reread your paragraph. You mean writing an interpreter that outputs C (or C++) code, and passing that to G++. That's definately a possibility, but we're kind of looking at VMs here, for multiple platform support.
    ZQJ
    ZQJ
    Quote:
    Original post by _goat
    I think what you're getting at is similar to the idea of concepts, such as:
    concept Vector{    // ...}concept Scalar{}V operator * <Vector V, Scalar S>(const V& lhs, const S& rhs);V operator * <Vector V, Scalar S>(const S& lhs, const V& rhs);


    Although using the * operator for the dot-product is bad mojo. In this way you can say "only Vector types (note that Vector is not actually a datatype, but just the concpet of one) can be used in this function, along with Scalar types".


    Well, I agree that using * for dot product is questionable, but I stand by the rest of the definition.

    Quote:

    Quote:
    On the compilation front I have to say I still support a gcc frontend. I don't think making a gcc frontend is particularly straightforward but it does buy a good amount of optimizing power and is probably easier than doing a compiler from scratch.


    I actually have no idea what you're talking about. A G++ frontend? What's the frontend of a compiler? Wait, no, I just reread your paragraph. You mean writing an interpreter that outputs C (or C++) code, and passing that to G++. That's definately a possibility, but we're kind of looking at VMs here, for multiple platform support.


    No, gcc supports multiple languages. Each language provides a frontend which converts the languages code to a generic form (called GENERIC I think), which is the optimized and compiled by the backend. Have a look here.
    ZQJ
    ZQJ
    Quote:
    Original post by _goat
    No, many things are unprovable - however, with the aforementioned structure, we actually have to write the code that will evaluate to a boolean expression. We're not writing abstract concepts, such as "function should make sure that pointer P is initialised to a correct memory address" - which is tricky to tell (although possible if you really wanted to hamstring your programming language). No, we'd be doing (P != NULL), and just hoping that they don't pass in an unitialised pointer, pointing to crap.


    Actually, I'd like to ask a question on this subject. People often say that many things are unprovable and usually cite either the halting problem or Godel's incompleteness theorem. As I understand it, the halting problem effectively states that it is not possible to construct an algorithm which can prove any non-trivial property of all functions/algorithms; however it does not state that such proofs do not exist.

    I don't really understand what Godel's incompleteness theorem implies, because from what I can gather it is connected to both rational numbers and first order logic; and I'm not sure whether or not proofs about computer algorithms fullfill the necessary conditions for it to apply.

    Topic Locked

    This topic has been locked by a moderator. New replies are not allowed.

    Sign in to reply to this topic.