Jump to content
  • Advertisement
  • entries
    359
  • comments
    237
  • views
    190047

About this blog

Current topic is the development of a toy language to test a few syntax ideas.

Entries in this blog

 

Back to work!

My vacation is over. It's useful to remind myself every so often why I don't travel and hate people. I did take some time and think about what I wanted to use my spare time for. In the end, I decided to use it for whatever the hell I want. So I'm going to try to do a quickie rewrite of Tangent with lessons learned and a renewed attempt at Moe. Ideally, two projects will keep me busy coding and provide enough varied problems that I don't get stuck on one problem where I don't have enough time/intelligence/skill to get through it.

First, a rehash of Moe. Moe is a placeholder name for a game I've had in mind for a little while now. It is a fantasy, turn based, 4x game. The closest game to it is probably Master of Magic. The main differentiator in the game idea is a de-emphesis on warfare.

The idea is to keep warfare viable, but not the hands down best way to win. Push it towards the desperate player or the player who needs might to make up for other failings. The two sides of that goal are fairly straightforward; make war expensive, and make peace an alternative means of conquer.

The key way war is being made expensive is by making units finite. Your population will be born, grow old, and die (and occasionally be raised as zombie labour). Losing population in even a successful war (or the lack of births due to wartime) is a non-trivial cost.

Making peace a means to conquer is more tricky. Civilization tried to push culture as an option, but it was always trumped by war. Too slow, too narrow. Moe aims to push the general concept to a bit more wide-ranging scope. Technologies will flow naturally towards more successful trading empires. Heavy trade increases happiness and desirability of your cities. Technological superiority breeds dissention in your neighbors. Desirability will allow you to siphon off immigrants from neighboring empires. Expansive trade routes allow armies to range farther and fight longer.

Unfortunately, it seems that XNA/SlimDx UI libraries are few and far between. reimplementing a UI isn't something I'm looking forward to. So at least for now, most of my energies are focused on Tangent again.


Mostly, this Tangent rewrite is going to take lessons learned and help make it more solid from the get-go; slim it down. Properties are out. Indexers are out. (just use phrases to implement them). Tuples are out; generics are de-emphasized. Must get users! Error reporting must be there from the start.

The biggest change though is probably going to be actually compiling into something. The last implementation was just way too slow. I spent a bit too much time futzing about reinventing the VM wheel. I've not decided what I'm going to compile into yet. Maybe C# and then recompile that. The DLR seems an interesting option but the docs are poorly written and/or over my head. Straight to MSIL seems to be the least pleasant option.

Multiple dispatch and the funky type system are the biggest things that are out of the ordinary for other VMs. Something I'm going to need to think about before I set to work on that. For now though, the parser(s) have been slimmed down and better (but still terrible) error reporting run through them. A basic compiler shell is there with better (and actually not bad) error reporting. The in-memory type representations are mostly back, with a few decisions yet to be made.

More to come as it gets done.

Telastyn

Telastyn

 

Programmer Archetypes?

I recently got back into playing Magic: the Gathering after some years away. The game has improved greatly since my departure, so kudos there but not what prompts a journal entry today.

Something I found out about today was this article by one of the card designers that describes the three archetypes of magic players that they've identified and catered to. Very similar to the mud/mmo paper that I hope you're all familiar with.

There is though one notable difference. The heart/spade/diamond/club paper describes mostly what people like to do in the game. It focuses on needs that the game designer must fill. The magic archetype model focuses more on what tickles certain players' fancies since each player essentially follows the same process while playing a game.

And mulling it over today, I thought that the magic article describes a fairly good model for programmer archetypes. It makes sense, since the game was originally designed to help teach certain programming concepts. For those that didn't read the article, here's the quick and dirty:

Timmy: This player likes to make a splash. They don't look at downside so much, just powerful effects, solid creatures. Swarming and going overboard are good too. A memorable victory or particularly gruesome overkill will make up for a number of losses.

Johnny: This player likes to create things. They won't ever just take a deck from someone else or the internet. Taking the various cards and creating something unique or under some odd constraints is often more fun than the game. Getting a quirky deck to beat the 'consensus pick' will make up for a number of losses.

Spike: This player likes to win. They are happy playing the same deck over and over again, as long as it wins. They're also happy to take decks off the internet or just buy their way to victory. A win is a win to these players; losses are unacceptable.

And of course these things are just stereotypes. All players fit somewhere between these extremes, with a certain mixture of each.


Each trait lines up with programmer behaviors that are beneficial, and some that become vices when taken to the extreme. Looking at programmers I've known, they too tend to fall towards these categorizations.

Timmy: The programmer that likes power. They probably got into programming to 'make the computer do things' or show off to friends. They love automating things, making flashy apps (that maybe don't work quite right). Their vices are feature creep, over-engineering, and occasionally an unreasonable tendency towards low level programming. They provide vision for a project, and at their best are the team members who just extrude useful little tools and enhancements.

Johnny: The programmer that likes creation. They probably got into programming as an artistic outlet, or as a natural expression of problem solving. They love creating new things and solving weird problems. Their vices are 'not invented here' syndrome, being too 'clever' while programming, and occasionally a lack of attention to mundane or practical concerns. They provide solutions for a projects, and at their best are the ones who solve the hardest problems and create the most elegant solutions.

Spike: The programmer that likes production. They probably got into programming as a means to an end; perhaps to make a mod or automate some task. They love getting things done, now. Their vices are disregard of usability, cutting corners with testing/maintenance, and occasionally low technical knowledge. They provide drive to a project, and at their best are the team members who pump out code and keep the rest in line with their uncompromising demand for production.


The most interesting thing I at least noticed was that an ideal team requires a mix of these sort of archetypes to keep each other in balance. Another thing I noted was that none of the archetypes was the 'perfectionist' sort. Someone who desired quality over anything else. That would mean that programmers by default don't like testing, which I'm not sure is true. It might be that there's a style of programmer missing from here. In the original article, the sort who needs to tune and refine something to the best it can be falls into the Spike archetype. Perhaps then that should be split into the 'make stuff, be proud of it' and the 'hacker' archetypes.

I'm not sure. What do you think?

Telastyn

Telastyn

 

And so it goes...

I've decided to let my gamedev subscription lapse. The main thing I used it for was for this sounding board to discuss my personal programming projects. It's been a few months since I last posted, and over a year since I've done any actual game related discussion. And even over the years I never really saw a lot of feedback or discussion that really made the posts satisfying. With my workplace gearing up for a big release, I probably won't have the time or motivation for personal projects until that's done.

I'll still be around, but I just can't justify paying the (relatively small) cost of the subscription for a cartoon cow and a journal I rarely use; especially these days. Perhaps I'll re-up once I start doing more development again, or get more disposable income.

Telastyn

Telastyn

 

Tangent: Haitus

I realized the other day while working on something barely non-trivial in Tangent just how shoddy the performance is. Memory usage, leaking, actual execution speed... And there's not a few things that are just bleh in the project itself. Combined with the lack of actual active interest by anyone who isn't me, and the renewed desire to work on other things I'm going to put Tangent down for a little while. Maybe make the source available once I clean out the worst of the memory leaks. Not that I won't come back to it, but I think other projects might do me a little good. Maybe even make Game Development posts on gamedev.net!


And at the very least, Tangent has done exceptionally well in its original goal of being a learning experience and a prototype. While it's fresh in my memory, some post-mortem like review:

Good Stuff

Phrases - This has a few parts; infix parameters, explicit identifiers, juxtaposition as application... This is 'what makes your language different?'. It was very powerful, elegant, intuitive. What else do you want?
Order of Operation inference - I personally never encountered woeful mis-inference. It wasn't super slow. It allowed certain syntaxes that were pleasingly unencumbered by decoration.
Multiple Dispatch - Especially with phrases, this had little downside, while freeing programmers from the 'to specialize you must sub-class' bindings.
Structural Typing - Allowed a certain flexibleness when doing design that was unfortunately lessened by free functions. Still, it seems the way to go.
Goose Types - And being able to put a 'normal' class hierarchy ontop of the type system with a mere keyword is elegant and useful.
Multiple Inheritance - No headaches when actually implementing it (beyond constructor vs invariant fights). I still think this will be a boon once more OO is done with the system.

Bad Stuff

No Community - No input, no people actually using the language pushing for quality or certain features, or just debating the utility of some ideas.
The Runtime - it was easy to implement, but took a little time with certain concepts, and the major source of performance issues. Plus there's a few little things I forgot, or did a shortcut with that are awkward now. It should've gone to the CLR (at least indirectly) as the original concept envisioned.
Too much backwards compatibility concerns - Originally, C# was to be more integrated. This provided a few too many constraints on design and too much demand on the naive way about how it should be implemented.
Tuples - Annoying, special case sort of constructs.
Visibility - The language tended towards 'classes are just records' style design, which didn't need or rely on visibility too much. Protected becomes kinda moot once inheritance acts oddly. And visibility mismatches created not a few type-mismatch bugs.
Generic Replacement - The implementation of generics replaces (or actively binds) instances into parameters rather than just referencing them. Big, ugly. Generics themselves are still of dubious utility.
Idealism around certain bits - Types really should know where they are declared. Scopes should be smarter about saying what things should be. A dozen other little things.
Little separation between instance generators, type classes, and type constructors - This one is inherited from C, but it becomes more apparent during implementation just how broken the idea of using a single concept to describe 3 separate purposes.
No 'abstract type' for operations - In the OO world, there's the concept of abstract types. 'This type can do X, Y, and Z'. Functions lack an analogous concept. 'My parameters can do (or must be able to do) these ops.' Dynamic languages kinda get away with it by just doing the operations. Type inference models can do that via that path. Originally, operators were going to be members (ala Java) and thus an abstract class could imply what operators worked. Tangent unfortunately needed that concept, but it was not included in design.


And next week I am on a cruise. Some nice R&R time to consider what I'd like to work on. Maybe more Tangent, maybe a new 'with lessons learned' implementation, maybe another go around at my fantasy 4x game idea. We'll see then.

Telastyn

Telastyn

 

Tangent, now with usable error messages!

In a long overdue effort to get people to actually use the software I write, the Tangent rehash now provides line numbers with error messages. w00t!


public goose class foo{
public bar x;
}




moocow.tan(2,9) : error : Unknown Type 'bar'

Telastyn

Telastyn

 

Links and progress

Happened across a nice (new) article by Bruce Eckel that I think very aptly describes C++ (and Java) in today's world. Always refreshing to see someone who is published explain something more clearly and concisely than I could.

I also happened across the Fan programming language a few weeks ago, but a reference to it in Eckel's blog reminded me to re-post here. It fits into that same sort of 'something like Java/C# but with first class functions and less rigid type structure' family of languages that Scala headlines and I'd like Tangent to be.


Speaking of which, the big bug problems of late last week have allowed for a flurry of smaller bugfixes and positive test results today. Most important of these at the moment is the ability for generators to be infix operators. Since there's no for statement, there needs to be a range generator to cause the same behavior. At the moment, I'm likely to use to as that operator with something like up to to be the exclusive version. ie


foreach( int x in 1 to 5 ){
print x; // 12345
}

foreach( int x in 1 up to 5 ){
print x; // 1234
}



Much more Tangentlike than range(1,6); or even 1..6

Also tested were some of the simple generic method syntax. I unfortunately will probably need to break the syntax that is there (away from C# syntax) in order to do specialization in a non-psychotic manner. Though probably not soon. I've yet to actually make generic parameters visible in methods, making them kinda useless.

Telastyn

Telastyn

 

Tangent: Syntax reworking

I'm looking to do a little reworking in the Tangent syntax, parser and compiler. Right now there's a little too many exceptional cases. The main candidates for removal are properties and indexers. They'll still exist, but will be done in the phrase style. No more special cases.

The first step is done. I took the degenerate case where a method has no parameters, and made that a simple getter:


public static pi => decimal { return( 3.141592 ); }


Setters will look a little odd, but similar to other phrase definitions:


public class SetExample{
private int _foo;
public Foo = (int value) => void{
_foo = value;
}
}


The behavior of each isn't really going to change, just consolidating the syntax and compiler a bit.

Telastyn

Telastyn

 

Tangent: Statement Documentation

Busy weekend. Took some time to update and flesh out the documentation, finishing out statements. As always, feedback from various levels of programmers is helpful.

Telastyn

Telastyn

 

Tangent: Pattern Matching, Part 1

Yet more motivation yesterday, so more Tangent advances. That, and the example code today is pretty sexy so stick around!

The first minor fix was finishing off the last little bug with generics. The basic stuff (generic fields in a type, generic parameters inferred in a method, method referring to the type's generic params) now work.


The second addition was syntax to allow for explicit declaration of generic parameters for a method. The normal (quick) way to declare a generic method in Tangent is something like:

public foo( arg) => returnVal

The explicit syntax allows for a method modifier with the syntax:

generic(generic-declaration-list)

which then looks like:

public generic(Any T) foo(T arg) => returnVal

A little less typing if you're going to refer to T a lot. It also allows for a little easier use when you need not just T, like if you want to infer the parameter from List.


The third bit of work was making sure that the type inference code I have is smart enough to deal with non-trivial inference. It turns out that it was smart enough, with no changes. Thus you can get a basic sort of pattern matching now within the language.

Which leads us to the example code of the day. Printing the default type value is currently the best way to properly detect that the types were properly inferred.


public class Printable{
public abstract ToString() => string;
}

public static default => T{
local T rtn;
return(rtn);
}

public static generic(Printable P, Printable R)
TestInfer( P -> R method ) => void{

print default;
print default;
}

public static main()=>void{
TestInfer( (int x)=>decimal{} );
}




In the real world, this sort of thing will more often be used for method modifiers, such as this not modifier (that does not quite work yet):


public static generic(Exists P) not( P -> bool predicate ) => P -> bool{
return(
(P arg)=>bool{
return( not predicate arg );
}
);
}

public static main()=>void{
print (5 not equals 4);
}



Telastyn

Telastyn

 

FLU!

Not dead. Mostly. Last week was sacrificed to the flu. Re-working a large/nasty method continues. Operators work again, and I found a few little bugs that never worked in the first place. Operators are now auto-detected by where you put the name of the method in the phrase:


foo(int x, int y) => int {} // foo - not an infix operator.

(int x) foo (int y) => int {} // foo - an infix operator.


Phrase work is partly done. I need to now do the code generation to do the automatic partial application. Hopefully it'll be cleaner and more consistent this time. More later in the week.

Telastyn

Telastyn

 

Victory!

No Tangent work today.

Spent the evening dominating a mtg draft tournament with one card.

Telastyn

Telastyn

 

Tangent: Code Examples

The documentation process continues. I went through a good number of the Rosetta Code entries, and created Tangent example code wiki entries for them. There's now about 8 times the example code entries for random programmers to view (even if most of them a simple, isolated feature examples).

Telastyn

Telastyn

 

Oh look, I was right.

Sure enough, waste of time. At least the last few places have been tech specific, with technical recruiters who at least knew the distinction between say... systems administration and software engineering.

Telastyn

Telastyn

 

Tangent: Pattern Matching, Part 1

Yet more motivation yesterday, so more Tangent advances. That, and the example code today is pretty sexy so stick around!

The first minor fix was finishing off the last little bug with generics. The basic stuff (generic fields in a type, generic parameters inferred in a method, method referring to the type's generic params) now work.


The second addition was syntax to allow for explicit declaration of generic parameters for a method. The normal (quick) way to declare a generic method in Tangent is something like:

public foo( arg) => returnVal

The explicit syntax allows for a method modifier with the syntax:

generic(generic-declaration-list)

which then looks like:

public generic(Any T) foo(T arg) => returnVal

A little less typing if you're going to refer to T a lot. It also allows for a little easier use when you need not just T, like if you want to infer the parameter from List.


The third bit of work was making sure that the type inference code I have is smart enough to deal with non-trivial inference. It turns out that it was smart enough, with no changes. Thus you can get a basic sort of pattern matching now within the language.

Which leads us to the example code of the day. Printing the default type value is currently the best way to properly detect that the types were properly inferred.


public class Printable{
public abstract ToString() => string;
}

public static default => T{
local T rtn;
return(rtn);
}

public static generic(Printable P, Printable R)
TestInfer( P -> R method ) => void{

print default;
print default;
}

public static main()=>void{
TestInfer( (int x)=>decimal{} );
}




In the real world, this sort of thing will more often be used for method modifiers, such as this theoretical not modifier:


public static generic(Exists P) not( P -> bool predicate ) => P -> bool{
return(
(P arg)=>bool{
return( not predicate arg );
}
);
}

public static main()=>void{
print (5 not equals 4);
}



Telastyn

Telastyn

 

Tangent: v0.28

I took some time tonight to nuke the last showstopper bugs so that I could make a midpoint release of Tangent. There's still plenty of bugs, but it'd been too long since a release. Not that anyone is downloading it, but one less excuse.

This release adds:

- A tiny command line compiler to the package for the mono users.
- The new Arguments => ReturnType syntax for methods.
- Better support for phrases.
- Support for operator symbols in phrases.
- Auto identification of infix methods.
- Support for generators via the yields return type.
- Better support for generics (still mostly broken).
- Better support for .NET imports.
- The -> type operator to succinctly define delegate types.
- foreach.
- The 'to' generator for ranges of integers.
- Improved support for 'this' methods.
- Statics (still a little flakey)
- Enums (barely implemented)
- ... and the usual assortment of bugfixes and random improvements.

Documentation on the site is still old. I'll take care of that in the coming week or two. Error messages are still terrible, and debugging info non-existent. That'll take a bit longer.

Telastyn

Telastyn

 

Tangent: Using

After exceptions work, the next step is the using block. The syntax is slightly different from C#. You can't have two elements in a using block (I forgot/didn't know you could even do that). And you can't just put a single expression after the using bit. Only the actual block, or another using segment. I was lazy and didn't implement the null check in the generated code (bug #77), so don't using something and then set it to null or fubar the initialization.

Probably now I'll go for a little release to get basic Dictionary importing, exceptions and using available (even if no useful .NET disposable objects are available yet...). Then it's time for bulldozer refactoring. The organization of the code is absolute trash, even without considering all the places where it's just architected oddly.

[edit: and there you go, version 0.29]

Test code of the day:


public class foo{
public Dispose()=>void{
print "disposing...\r\n";
}

public virtual Moo()=>void{
print "moo.\r\n";
}

}

public class bar:foo{

public Moo()=>void{
print "MOO!\r\n";
}
}

public static main()=>void{
using( foo x = new foo )
using( foo y = new bar )
{
x.Moo();
y.Moo();
}
}



Telastyn

Telastyn

 

Tangent: Mines!

I did a quick little update to fix infix operators that yield, and everything went to hell. I mean Console.WriteLine stopped working. A tiny program that used to take half a second to compile is now taking 11 minutes, and pukes null reference exceptions...

I fixed the first problem, and the second might just be caused by the import grabbing almost all of the .NET libraries rather than 8 mostly empty classes (and then me dealing with them stupidly). The third is... something.

Not a very productive night.

[edit: Helped compile times. (20s vs 11m30s) Constant is better than linear, mmmkay.]

Telastyn

Telastyn

 

Tangent: Statics

Had a little extra time tonight to work on static methods and variables, and now they work:


public class foo{
public string bar = "moo.";

public static int baz = 6;
public static genFoo(string initValue) => foo {
local foo rtn = new foo;

rtn.bar = initValue;
return(rtn);
}
}

public static main()=>void{
local foo Foo = new foo;


Foo = foo.genFoo("bleat.");

print Foo.bar; // bleat.

print foo.baz; // 6
}



This turned out to be one of those things that looks simple and should be simple, but is just a pain to implement. Even though it's 'working' now, I'm marginally afraid to do anything more complex than the example code. I can practically hear the bugs crawling about in the hackery used to get it working.

That leaves 'this' methods and generics (and the inevitable debuggery from this mess) in this batch of cleanup. Far too much. I must continue the focus on making little hard examples work. One tiny step at a time.

Telastyn

Telastyn

 

Tangent: Generic Method Bodies, Part 2

Yet more time yesterday, so more work into generic methods. On the slate was type parameters, using generic references as the return type and resending the generic to another generic. The example code is fairly simple today; a in-source re-creation of the C# default keyword.

Remember that Exists is the super-type of everything and that Any is the super-type of everything but void. And local variables are default initialized out of the box.


public static default => T{
local T rtn;

return(rtn);
}

public static factory => T{
return(default);
}

public static main()=>void{
defaultvoid>;

print defaultint>;
print defaultdecimal>;
print default;

print factoryint>;
//factory; // error as expected.
}


Telastyn

Telastyn

 

Tangent: IDE?

I had a little time today so I fixed up member access. foo(a,b,c).bar() now will work as expected and a few other oddities around member access have been corrected. As an added bonus, the code around them is smaller, cleaner and more kickass.

I also took a few hours to knock up the worst IDE known to man. Textbox for input, textbox for output, button to compile. Woo. I'll likely need to add a little to it because I suspect Tangent to really benefit from IDE support. Stuff like knowing what that identifier actually is, what that statement really will resolve to, what the order of operations for that is going to be. Usually I expect that to be clear, but it'll be easier to write ugly/obfuscated code and I think even good coders will run into scenarios where the IDE will help.

Now I have somewhere to add that, and a practical bit of code to better judge what is required/useful.

Telastyn

Telastyn

 

Introspection

I realized something today. I do not learn advanced concepts well. This is a known problem. There's probably a lot of reasons why this is, and I have a decent idea about a few of them, but today I thought of a new one.

I am pretty smart. Or at least all the tests always said I was, and looking around for the past 20+ years affirms that. The key problem I've had for some time is that I might be a little too smart, and it's led to problems later in life.

I remember when I was young my father (a mainframe programmer) would get calls late at night when a program went bad. He'd sit there, right after being awoken in the middle of the night without a computer and quote line numbers to the guy on the phone regarding what code to fix. My childhood memory wasn't quite that good, but spelling tests are easy when you can recall the image of the word in the spelling book.

The other thing that made schoolwork easy was the ability to pattern match and do kind of extrapolation. A sentence's grammar is something of this type followed by a different type, followed by... fits mentally right in with algebra behaviors. And that's usually how I'd learn new things. The new thing follows this pattern, or the new thing behaves like this known thing.


So these sort of things were great in school. Most of (US, public) school is just memorizing and regurgitating things. The rest is learning pretty similar concepts in a vaguely different form.

Now as an adult, they're kind of sucky. My memory is mostly gone. I'll remember the shape of the license board in FFX or where we left off in the last D&D campaign or the ID of the user I worked on yesterday or who the Steelers quarterback was when they tied Atlanta... but not reliably anymore. And code? No way. It doesn't fit into the shape or pattern or however my memory likes it.

And as it turns out, mapping new concepts into old concepts only goes so far. It goes a hell of a long way mind you, but eventually you need (a few) new concepts to really know something different. And it's hard to get them when you've never needed to.

Perhaps more significantly, I have problems communicating certain things to people. I'll tend to describe coupling oddly for example. That the data organization should line up like a tree; just as actual personnel organizations and areas of responsibility; just as a graph of sciences and their interactions or a game's tech tree. I tend not to make any distinction between any of them, and the abstract concepts of relations, interactions, parents, 'weak' sort of ownership are all still sort of there even if they're not commonly used in that particular tree. And that leads to problems sometimes when other people just don't think of them that way.


Anyways, as I was saying, I realized something today. Another facet of learning problems I have is when people abstract stuff for me. I was looking at the wikipedia entry for Limits in category theory and my brain shut off. Not exactly surprising. But this time I realized why I hate greek lettering and the general 'blah is defined as blah op blah to blah blah blah op' that is universal to higher math resources and not a few programming language books/articles/guides. I can't conceptualize greek.

I just can't form a symbol in my head to represent the first element of the relation/equation. X is fine. I know what X looks like, what it sounds like, and reading it I can get a handle to 'some placeholder named X'. Greek? Can't do it. Things that I'm not sure are placeholders, or are some new abstract concept I don't know? Can't do it.

Further, I don't learn by taking an abstraction and specializing it to cases. I learn by taking hard examples (which give me nice solid things to use as symbols/images while thinking) and extrapolating them into the general case. So compare that wikipedia article to this haskell tutorial regarding list comprehensions. That tutorial is what kinda set off the light bulb for me today. It was the first thing I thought of after my brain rebooted. It's the same sort of math gibberish I have problems with, but it starts with an example. No problem at all learning what it is and even the mathematical notation it's based off of.

It starts with a nice set as the visual symbol and then edits it as the tutorial goes along describing what the example comprehension is/does. It describes what everything is in the example, and relates it back to the mathematical roots so that mentally I can make that footnote. It then does progressively more complex things, but always again from an initial state. It works fantastically for me; someone who starts with a known concept and maps new concepts to it, expanding or adapting the original concept as needed.

Telastyn

Telastyn

 

Tangent: Visibility, Part 2

Part 1

The change so that private fields get their own storage is finished. I need to review some of the other visibility related things (name lookup for standalone fields, method dispatch) to finish that snippet of changes. Then will be a release.

A nice side effect of this private field storage change was fixing the bug that prevented static member's initializers from working.

The test/target code for the change:


public class foo{
private int x = 4;

public foox()=>void{
print x;
}
}

public class bar{
private int x = 9;

public barx()=>void{
print x;
}
}

public class foobar:foo, bar{}

public static main()=>void{
local foobar tmp = new foobar;

tmp.foox();
tmp.barx();
// print tmp.x; // properly does not compile.
}





[edit: Also, some documentation regarding the algorithm used to infer the order of operations.]

Telastyn

Telastyn

 

Tangent: Enums

After doing some of my own ruminations on the subject, I made a post to the community at large to get some input/ideas for enums. Most people seem as if they'd be fine with C# enums. I don't think I'd be fine with C# enums in Tangent.

I'm not completely sold on their design yet, but the current basic implementation is fairly Java-style enums. The actual constructs themselves are sugar for some global, constant goose type instances. A individual enum value is a class instance that is a sub-type of the abstract enum class. Since they are just classes, you the programmer will be able to define methods, fields and properties on the enum class and by extension the enum values. And methods will be able to be specialized on a particular enum value, just like any other subtype.

Currently enum values have a sane ToString defined, and the enum class (as well as the global scope) has static properties that return the enum values by name. The values themselves live as static tuple members on the enum class (as you'll see below). That is likely to be hidden or abstracted later. Enumerating through the enums and specifying specializations are not done yet. Other stuff will be driven by suggestion or more likely, personal need when doing example apps.

The current testapp (yes, yes I need to get == working again...):


public enum CardSuit{
values{
club,
spade,
heart,
diamond
}

public foo()=>void{
print "foo.\r\n";
}
}

public static main()=>void{

CardSuit.tuple[0].foo();
CardSuit.diamond.foo();

if( CardSuit.tuple[0] equals CardSuit.tuple[0] ){
print "equality works.\r\n";
}

if( CardSuit.tuple[0] equals CardSuit.tuple[2] ){
}else{
print "inequality works.\r\n";
}

if( CardSuit.club equals CardSuit.club ){
print "equality works.\r\n";
}

if( CardSuit.heart equals CardSuit.diamond ){
}else{
print "inequality works.\r\n";
}

print CardSuit.heart "\r\n";

local CardSuit suit = CardSuit.club;
print suit "\r\n";

suit = CardSuit.diamond;
print suit "\r\n";

suit = spade;
print suit "\r\n";
}




foo.
foo.
equality works.
inequality works.
equality works.
inequality works.
heart
club
diamond
spade


Telastyn

Telastyn

 

Tangent: Method Tests Part 2

Not much time for hobby this weekend. I managed to setup some delegates and make sure they work like they're supposed to. The example code, which includes infix delegates and a quick example of the partial application built into the language:


public static foo() => void{ print "foo.";}
public static bar(string s) => void{ print s;}
public static baz(string s, int i) => void{ print s i;}
public static phrase(string s) (int i) => void{ print s i;}
public static how now brown cow => void{ print "MOO!";}
public static test (int lhs) times (int rhs) => int{ return lhs * rhs; }
public static (int lhs) op (int rhs) => int{ return lhs * rhs; }
public static (string lhs) * (string rhs) => string{ return lhs + rhs; }
public static (string lhs) ++ (string rhs) => string{ return lhs + rhs; }
public static (int x) a b => int{ return x+5; }

public static delegate voidDel() => void;
public static delegate (string lhs) opDel (string rhs) => string;
public static delegate what now brown cow => void;
public static delegate cowDelegate cow => void;

public static main()=>void{
foo();
bar "moo.";
baz ("bleat.",6);
phrase "bleat." 42;

how now brown cow;

print test 4 times 6;
print 2 op 3;
print "moose:" * " umm. moose.";
print "moose:" ++ " umm. moose.";

//print 5 a b; // bug #37

voidDel = foo;
voidDel();

opDel = +;
print "moo" opDel "cow";

opDel = ++;
print "bleat" opDel "sheep";

what = how;
what now brown cow;

cowDelegate = how now brown;
cowDelegate cow;

voidDel = ()=>void{ print "llllama."; };
voidDel();
}


Telastyn

Telastyn

 

Tangent: Exceptions

Spent some time last night implementing exceptions. Nothing too special here. try/throw/catch/finally as they exist in C#. Under the hood, I just use the existing exception mechanism to do the delivery, and wrap exceptions so that the runtime can distinguish between exceptions raised in the runtime and exceptions raised by the runtime.

The two main differences are that you may throw any object, not just exceptions and that the catch parameters use Tangent types. So the catch uses structural subtyping to see if an exception matches it. Not big changes, just little things to keep the feel of the language consistent.

The example test code of the day:


public static main()=>void{
try{
//throw "moo.";
//throw 42;
throw 3.14;
}catch(string speech){
Console.WriteLine(speech);
}catch(int count){
Console.WriteLine(count);
}finally{
Console.WriteLine("finally.");
}
}


Telastyn

Telastyn

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!