🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Idle: Wished-for programming language design?

Started by
36 comments, last by cr88192 11 years ago

so, the idea here is basically, thoughts for what a person might want in an "ideal" programming language.

granted, some limits may be set, as what is ideal for one person may not be ideal for another.

so, for example, a few general thoughts:

mostly a "fairly generic" syntax, like say a mixture of C, C++, Java, and C# syntax;

can be either compiled to native, or compiled to bytecode and run in a VM;

should have easy access to existing C (and ideally also C++) libraries;

should have some built in mechanisms for internal security and sandboxing (pieces of code within the program can be run with reduced rights, ...);

should have the ability to load bytecode and source programs at run-time, accept dynamically created bytecode, and support an "eval" mechanism;

probably includes optional variant and auto-typing as well (variant-typing being dynamically-typed with optional type-inference, and auto-typing mandating that only a single type be used);

stuff should be portable between OS's and CPU architectures;

...

more specific thoughts:

may use a Java-like class declaration syntax (and probably Single Inheritence + Interfaces);

may use a C#-like package/namespace system, and allow more free-form contents declared in source files;

uses a C#-like parsing strategy (mostly avoids the issues of ordering and context dependence from C and C++, and doesn't depend on a few of the "tricks" used in parsing Java, *1);

probably includes a few other features like in C#: pointers, references, structs, properties, operator overloading, ... (*2)

interfaces likely support default methods and fields (*2);

probably uses more of a "nearly everything is an expression" syntax design (*3);

...

*1: C# basically defines the syntax in terms of more rigid rules which don't depend on declaration context (like C or C++) or on external context (Java).

*2: pointers can be made "safer" by supporting implicit bounds-checking, and possibly by placing some limits on allowed pointer type conversions. in most cases, this can be made fairly invisible to code using the pointers.

other features would likely be similar to their analogues in C#, though a property syntax more like AS3's could be considered (slightly less funky than the C# property syntax).

*3: a default method allows a method implementation to be provided in an interface, and a default field would allow field declarations within an interface. in effect this makes an interface more analogous to an "abstract base class".

*4: basically, like C, but possibly taken a little further. many statements are syntactically actually expressions, just put on their own lines. could possibly also consider adding the concept of tail-calls.

probably the "landscape" it would live in would build directly on top of the C landscape, with what exists as the "class library" existing to some extent as wrapper libraries. most C API wrapping can be done fairly automatically by tools, allowing C headers/libraries to be made available in a form resembling packages (or namespaces).

in my own language "BGBScript" I had called this concept "native packages" and "native import", where the idea was to allow packages to exist which directly represented parts of the C landscape, and could be used for importing/exporting to/from C land. most of the import/export work can be handled fairly automatically by batch-tools (basically, say, you make OpenGL available by, say, invoking a tool and telling it to use "opengl32.dll" and "GL/gl.h" and also give a few other settings, and it spits out any wrapper code and metadata). (a drawback is as-is, separate tools are used for importing/exporting, whereas ideally a single code could handle both at once).

there is a possible choice between "package ... { import ...; ...}" and "namespace ... { using ...; ...}", but this is more primarily a syntactic issue (both would be functionally equivalent).

thoughts?...

Advertisement

My ideal language:

A new verion of C# / .net

Without nulls

Everything is a reference type (can be toggled off on the compiler/ using some form of blocks/ Explicitely declaring some types as NonReference and having an error when passing them where a ref is expected etc) so that there's no 2 basic types for the (very large majority) of applications where speed just doesn't matter at all.

Non backward compatible : remove all legacy features and APIs

MyClass.Members.Test.PropertyName (can be solved by the compiler at compile time, types wouldn't have to have a Members property actually available at runtime, would just be an extention keyword and enable a lot of scenarios which require reflection or AOP to be available built in and at compile time without any safety loss from working with strings)

issue:
nulls, and value types, are actually pretty useful in many cases, and there are still many cases where performance does actually matter...
actually, for practical languages, the concept of null is likely all but inescapable.

also, ease of getting things done effectively is also important, and something like lacking nulls and value-types would likely result in a lot of convoluted code trying to work around it (the lack of user-defined value types is already an issue a lot of times when it comes to writing code in Java, and taking away null would likely make all this a bit worse, and probably just result in people poorly recreating it via a Null monad class or similar...).


to reduce the possibility of null-related exceptions popping up at run-time, a compiler could potentially generate a warning though for cases where a null is likely to pop up and generate a runtime exception, and support a modifier to disallow passing null to certain functions (or assigning it to variables).

say, we write something like:


Foo! foo;
...
foo=null;


and the compiler is like: "no, you can't do that...".

which is basically the logical inverse of:


int? i;
...
i=null;

where normally a compiler would object to assigning null to an integer, but the '?' says it is ok.

Like in c++, there should be a language design idiom stating that you should not pay for what you dont use.

if theres any optional checking, safety or other dynamicisms, they should be optional and preferrably not the go-to method of doing things.

To make the language less horrible due to the lack of ugly dynamic language features, a flexible compile time metalanguageish system should be provided (templates and all, but more flexible, like running any code at compile time if possible. And not duck typed, so there can be code completion...)

o3o

Like in c++, there should be a language design idiom stating that you should not pay for what you dont use.

if theres any optional checking, safety or other dynamicisms, they should be optional and preferrably not the go-to method of doing things.

To make the language less horrible due to the lack of ugly dynamic language features, a flexible compile time metalanguageish system should be provided (templates and all, but more flexible, like running any code at compile time if possible. And not duck typed, so there can be code completion...)

generally agreed.

in language design, it is often a tradeoff between not providing a check at all, or making the check be implied and generally having the compiler optimize it away when possible.

having dynamic features as opt-in makes sense (this is partly how I had already been approaching things in my language, gradually moving away from using dynamic features as the default mechanisms).

safety related features are a little bit of a harder issue though, mostly because they may also have implications for code-security, and if there is a possibility that the code may be "untrusted", it generally makes sense for the checks to be enabled by default (and left more as an "opt-out" feature more like that of the C# "unsafe" keyword, where untrusted code using 'unsafe' may result in it being automatically rejected).

typically, a sort of limited form of generalization + specialization can be provided by variant and auto types.

typically, an auto type will only specialize the types once, requiring the types to be statically provable (basically, like the "auto" type in C++);

"variant" is a little less aggressive, and will more often work via one of several mechanisms:

will leave the check as a dynamic type checks (a generic/slow route), for cases where the type can't be statically determined;

will make specialized versions of the code specialized for each type it is used with.

a downside though is that handling the dynamic cases for variant does imply some runtime dependence, whereas auto can be handled without depending on the runtime (since if full compile-time specialization can't be done, the compiler will generate an error).

there is some implementation-level overlap with concepts like generics and/or templates.

the general problem with metalanguages which execute code at compile time is that there aren't really many good ways to do this which don't in-turn turn into an awful mess (this was my past experiences trying to bolt a Common-Lisp style macro-system on a language with a C like syntax). I can imagine the idea of trying to hammer together C++-style templates with CL-style macros, and this thought seems... disturbing...

so, I guess the thing would be coming up with a good idea for what such a thing should look like.

some ideas which I have ran across before have been for "static if()" and "static for()" statements, which basically tell the compiler "this statement will be handled at compile-time", with the the latter basically telling the compiler to unroll the loop in advance. granted, technically "const" or "final" would probably be a better choice here (would have less conflict with various ways in which 'static' is commonly overloaded).

one possibility for compile-time execution:


final int x=10;
...
final if(x>5)
{
    //loop executes at runtime
    for(int i=0; i<x; i++)
        { ... }
}
else
{
    //loop is unrolled at compile time
    final for(int i=0; i<x; i++)
        { ... }
}

final virtual int i=x;  //compile time variable (may need better keywords)
final while(i>0)
    { ... }
//expand while-loop branches at compile time, treating 'i' at each step as if it were a compile-time constant.
//likely
...

final {
    //code is executed at compile time (by default)
    ...
    dynamic {
        //code to be executed at runtime
        ...
    }
}

or such...

issue:
nulls, and value types, are actually pretty useful in many cases, and there are still many cases where performance does actually matter...
actually, for practical languages, the concept of null is likely all but inescapable.

also, ease of getting things done effectively is also important, and something like lacking nulls and value-types would likely result in a lot of convoluted code trying to work around it (the lack of user-defined value types is already an issue a lot of times when it comes to writing code in Java, and taking away null would likely make all this a bit worse, and probably just result in people poorly recreating it via a Null monad class or similar...).


to reduce the possibility of null-related exceptions popping up at run-time, a compiler could potentially generate a warning though for cases where a null is likely to pop up and generate a runtime exception, and support a modifier to disallow passing null to certain functions (or assigning it to variables).

say, we write something like:


Foo! foo;
...
foo=null;


and the compiler is like: "no, you can't do that...".

which is basically the logical inverse of:


int? i;
...
i=null;

where normally a compiler would object to assigning null to an integer, but the '?' says it is ok.

I'll have to disagree on the null topic, hell even the guy who created the concept of null disagrees and cites it as his worse mistake ever. If you think of it null is a very bad idea, it's a way to represent an incorrect state, so that you can check for that incorrect state later on, what's better is not allowing an incorrect state at any time and sticking to that, this means redisigning many APIs but then that's also why i wouldn't mind breaking changes. I would like a C# without null, without being able to declare something that would lead to null, without the null keyword etc.

I also mentioned enabling value types when needed, but most programs don't need it really. Most programs aren't games and have pretty much no arithmetic, actually most programs barely use value types at all except where the fact it's a value type doesn't change the semantics (used locally in a block). I don't think the concept of value types serves a useful purpose for everyday's programming, hell there's nothing inherently faster about them, don't forget that value types != on the stack, it's just an implementation choice on the compiler's side not a guarantee, the only actual diference is in use semantics, and that's not a good thing IMHO, a good tradeof would be to

- Have them be reference types (this is a semantic change)

- Add a layer of metata on functions indicating for each parameter if the parameter gets assigned in the function or a nested function

- If not pass it on the stack, still making it act as a reference type but hiding the fact it doesn't internally when it wouldn't change the outcome, no 2 mechanics, no 2 styles to learn, no errors due to passing a parameter and expecting it to / not to change etc.

'll have to disagree on the null topic, hell even the guy who created the concept of null disagrees and cites it as his worse mistake ever. If you think of it null is a very bad idea, it's a way to represent an incorrect state, so that you can check for that incorrect state later on, what's better is not allowing an incorrect state at any time and sticking to that, this means redisigning many APIs but then that's also why i wouldn't mind breaking changes. I would like a C# without null, without being able to declare something that would lead to null, without the null keyword etc.

I've heard this sentiment echoed a number of places, and being mainly a C++ programmer, any place where I have the luxury I use references, but there are many times where I have to use pointers instead of references. How do you handle the situation where you require delayed construction of an object? Or there are circular dependencies? I find I often come across cases where I can't initialize an object to a valid state till a while after the object is created/used. Some are trivial to work around, but not all. How do you work around this? For example, how would you implement a double-linked list?

'll have to disagree on the null topic, hell even the guy who created the concept of null disagrees and cites it as his worse mistake ever. If you think of it null is a very bad idea, it's a way to represent an incorrect state, so that you can check for that incorrect state later on, what's better is not allowing an incorrect state at any time and sticking to that, this means redisigning many APIs but then that's also why i wouldn't mind breaking changes. I would like a C# without null, without being able to declare something that would lead to null, without the null keyword etc.

I've heard this sentiment echoed a number of places, and being mainly a C++ programmer, any place where I have the luxury I use references, but there are many times where I have to use pointers instead of references. How do you handle the situation where you require delayed construction of an object? Or there are circular dependencies? I find I often come across cases where I can't initialize an object to a valid state till a while after the object is created/used. Some are trivial to work around, but not all. How do you work around this? For example, how would you implement a double-linked list?

or, even, say, implement a linked list with a finite length?... you need something to terminate the list with, and this is generally done with a null...

also, a null type is pretty useful when implementing something like a hash-table, where not all the entries will necessarily have valid values.

much better I think would be having an explicit "not null" notation, rather than eliminating null from a language...

now, as for people thinking things were a mistake:

there is also a tired argument that many people also believe that the concept of variable assignment is a mistake.

doesn't really mean that there is as much practical usefulness for languages which lack the concept of variable assignment though (they typically only really gain niche usage).

sometimes the benefits of a feature outweigh the costs...

'll have to disagree on the null topic, hell even the guy who created the concept of null disagrees and cites it as his worse mistake ever. If you think of it null is a very bad idea, it's a way to represent an incorrect state, so that you can check for that incorrect state later on, what's better is not allowing an incorrect state at any time and sticking to that, this means redisigning many APIs but then that's also why i wouldn't mind breaking changes. I would like a C# without null, without being able to declare something that would lead to null, without the null keyword etc.

I've heard this sentiment echoed a number of places, and being mainly a C++ programmer, any place where I have the luxury I use references, but there are many times where I have to use pointers instead of references. How do you handle the situation where you require delayed construction of an object? Or there are circular dependencies? I find I often come across cases where I can't initialize an object to a valid state till a while after the object is created/used. Some are trivial to work around, but not all. How do you work around this? For example, how would you implement a double-linked list?

Pointers have nothing to do with this, on the C# side pointers are one thing (used in unsafe blocks) and reference and values a whole other topic, so this is quite out of scope and unrelated to what i was saying.

'll have to disagree on the null topic, hell even the guy who created the concept of null disagrees and cites it as his worse mistake ever. If you think of it null is a very bad idea, it's a way to represent an incorrect state, so that you can check for that incorrect state later on, what's better is not allowing an incorrect state at any time and sticking to that, this means redisigning many APIs but then that's also why i wouldn't mind breaking changes. I would like a C# without null, without being able to declare something that would lead to null, without the null keyword etc.

I've heard this sentiment echoed a number of places, and being mainly a C++ programmer, any place where I have the luxury I use references, but there are many times where I have to use pointers instead of references. How do you handle the situation where you require delayed construction of an object? Or there are circular dependencies? I find I often come across cases where I can't initialize an object to a valid state till a while after the object is created/used. Some are trivial to work around, but not all. How do you work around this? For example, how would you implement a double-linked list?

or, even, say, implement a linked list with a finite length?... you need something to terminate the list with, and this is generally done with a null...

also, a null type is pretty useful when implementing something like a hash-table, where not all the entries will necessarily have valid values.

much better I think would be having an explicit "not null" notation, rather than eliminating null from a language...

now, as for people thinking things were a mistake:

there is also a tired argument that many people also believe that the concept of variable assignment is a mistake.

doesn't really mean that there is as much practical usefulness for languages which lack the concept of variable assignment though (they typically only really gain niche usage).

sometimes the benefits of a feature outweigh the costs...

Some things like linked lists would need to change a bit yes, i don't see a problem with that, i'd gladly embrace some change in exchange for getting rid of null. Also all languages don't need to be good for everything, as i mentioned those changes wouldn't necesarily be good for games / realtime apps, but for exemple in years working on business application development, i haven't needed a linked list once, not once.

If an entry doesn't have a hash value, then it shouldn't be in a hash table to begin with imho, so that's a positive vote for no nulls from my side, disallowing the kind of hacky "lets fix issue X by using null and changing the expected behavior" type of mentality that resides around it. If something can't properly be defined in a specialized collection, don't try to stuff it in that collection, and be glad the framework is telling you you can't!

And yes many people think that "X" or "Y" or "Z", what's noteworthy here is not that "someone" thinks that null shouldn't exist, nor even that someone significant thinks so, it's that the GUY WHO INVENTED IT thinks so, that's quite a huge diference in my book and definately noteworthy.

Sure you can find dozens of things you can't do if you remove nulls, but you must first think of 2 things : 1) are those things actually good? and 2) if i try to solve it without nulls, do i not end up with a better result?

May not be a good solution as i just think of it as i type but for example linkedlist could simply return element interfaces wraping the value with IElement having current / hasnext/hasprevious and being castable in IPreviousElement:Element if it hasprevious and vice versa, that way you could end up on an ielement that hasnext = false and you'd know it's not castable to an INextElementContainer , if you checked it you'd see it's underlying type is a FinalElement:IElement and that it doesn't contain any null properties. There, double linked list without null.

This topic is closed to new replies.

Advertisement