Advertisement

Angelscript language design and feature

Started by July 14, 2010 04:55 PM
11 comments, last by WitchLord 14 years, 4 months ago
@WitchLord

I think that good starting point will be single inheritance, because this model is widely used. Personally I didn't see multiple-inheritance model in C++ too much, it's sometimes used to define interfaces or mixins through templates, but class hierarchy inheritance is usually single (this is because many libraries have bindings to other languages which don't support multiple inheritance).

Personally I don't see drawback when limiting inheritance model to single. Multiple inheritance could be too complex, because of adjusting this pointer. I'm sure that for AngelScript will be better complete support for one inheritance model than incomplete or no support for inheritance, it's about priorities;-)



BTW: Great work. I finished making bindings for few of my classes (zero inheritance:)) and it's very straightforward. I added few macros and bindings for some class looks like this:

  _TYPE("IntRect", IntSize, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA);  _CONSTRUCTF("void f()", fsIntRect_Construct);  _CONSTRUCTF("void f(const IntRect& in)", fsIntRect_Construct_IntRect);  _CONSTRUCTF("void f(int, int, int, int)", fsIntRect_Construct_I_I_I_I);  _METHODM("IntRect& opAssign(const IntRect& in)", IntRect, operator=, IntRect&, (const IntRect&));  _METHODM("IntRect& opAddAssign(const IntPoint& in)", IntRect, operator+=, IntRect&, (const IntPoint&));  _METHODM("IntRect& opSubAssign(const IntPoint& in)", IntRect, operator-=, IntRect&, (const IntPoint&));  _METHODM("IntRect opAdd(const IntPoint& in) const", IntRect, translated, IntRect, (const IntPoint&) const);  _METHODM("bool opEquals(const IntRect& in) const", IntRect, operator==, bool, (const IntRect&) const);  _METHODM("IntRect& clear()", IntRect, clear, IntRect&, ());  _PROPERTY("int x", IntRect, x);  _PROPERTY("int y", IntRect, y);  _PROPERTY("int w", IntRect, w);  _PROPERTY("int h", IntRect, h);


It's really small and understanding of calling conventions inside AngelScript is killer feature.
Quote: Original post by WitchLord
Quote:
From what I've seen, AS is quite close to C++/Java -- While this looks great to you, as a real programmer, designer types most often aren't programmers. It may or may not be the case that your scripters and level designers (who may simply be you, yourself) are comfortable with "real" programming languages, so be sure you're choosing a scripting solution that's easy and intuitive for that audience, not just yourself.


This is a comment that I've seen quite often, and I can't quite understand it. The difficulty in programming is normally not the language but the logical thinking required to make it do what you want.

Someone with absolutely no programming experience will be able to learn pretty much any language just as easily, given that he has documentation and examples to learn from.

The difficulty in learning scripting for a game or application is definitely not the language, but rather the interface that the game or application exposes to the scripts.

The difference between statically typed and a dynamically typed language is the trade-off between compile time verifications versus runtime verifications. It may require a bit more up-front thinking from the programmer to write a correct program, as the compiler will not accept wrong types, but on the other hand there is much less runtime troubleshooting needed to fix incorrectly written programs due to mismatching types.


Without really wanting to turn this thread into a "merits of Angelscript" or "static vs. dynamic typing" I thought I'd respond to this one point.

The role that scripting fills, from an architecture and design standpoint, is mediating between the left-brain folks (developers) and the right-brain folks (designers). Catering to those two roles, any scripting language should be easily and powerfully embeddable into the host application (to satisfy developers) while also being able to express structures and concepts in simple and natural terms for designers.

Developers think of variables in terms of their properties -- Its an integer, its a floating-point number, its 32 bits, its 64 bits, its signed, its unsigned, etc because these are the details that matter to them. Their entire relationship with variables is formed around what it is capable of representing and how it does that.

Designers think of variables in terms of what they hold -- an enemy, and ammunition count, an inventory table because the minutia doesn't matter to them. In a designer's eyes, variables are just buckets -- a place to put things and retrieve them later.

You make a good point that the bulk of a designers work is not in interfacing with the core scripting language itself, but in expressing their goals through the API that the engine exposes through the scripting language. From what I've seen of AngelScript, and mind you I'm not that up-to-date on it, it appears to be mostly limited to expressing data, control structures and logic, and doesn't make too many great strides to express concepts at a higher level than those found in the languages which have inspired it, so my charge is not that AngelScript is too hard, but that the C lineage of languages from which it has taken its inspiration is intimidating to non-programmers and also carries a not-insignificant amount of baggage and mis-steps (if not outright mistakes) that I hope AngelScript has had the good foresight to not propagate.


This last part goes to the last paragraph I quoted, and also to points the OP has responded with regarding the performance of dynamically-typed vs statically-typed languages:

Its true that statically-typed languages have long-been the well-known perveyors of type-checked goodness, but static typing is not necessarily a prerequisite for the "correctness" and execution-speed benefits that static-typing has historically been associated with. We've grown to think of things in these terms because type-checking, and all that comes along with it, is far easier to do in statically-typed languages because, from a variable's inception until its final destination, we have errected guard posts marked "'int's only!" all along its path and you only have to go as far as the nearest guard-post to determine a variable's true type at that moment (presuming that the guard-posts are trustworthy). All those benefits are achievable in a dynamically-typed language, however the burden of proof required to be a certified 'int' is higher and more difficult to prove; no longer is the word of the last guardpost good enough, but you must prove that it is impossible, within the context of the program, that the variable standing in front of you is anything other than an 'int'. Certainly this is a much taller order, and one which may not be within reach of many scripting systems (particulalry interpretted or JITed ones), but it can be accomplished as part of the compile process, whether that is to real machine code or to VM bytecodes. In a perfect world, and if we are free to be blissfully ignorant of the underlying platform (as we should be in any scripting system), we would enjoy a sort of "mixed typing" where we users could treat a varaible as a simple bucket and let the compiler determine which type(s) a variable may be during a particular stretch of the execution path. This would allow types to "flow" without paying the overhead of genericity at all times.

Finally, you make a point that having a statically-typed language makes one think harder about types and about the architecture which enforces those types, ending with the implication,as I read it, that dynamic types are somewhat haphazard and dangerous, almost by design -- I don't believe that to be the case. If anything, I think that dynamically-typed languages require more thinking and planning than statically-typed ones, and at a level more akin to data-flow than simple API specifications. Normally, thinking harder would be a hard wrap to beat and make dynamic-typing a bit of a leper, but it also comes part-and-parcel with generic programming, making the codebase more fluid and avoiding the type-rigidity of strictly-typed languages. Its true that dynamic typing does make possible some truly eggregious type-errors that will only appear at runtime, passing a float to a function meant to concatinate two strings for instance, but those who frequently program in dynamically-typed languages will all tell you that this is not the type of mistake they frequently make -- and when they do, the cause is usually all too appearant. Compare this with the devilish "type" errors that can happen in an OOP language where some subclass satisfies the interface of its base, but not the intended semantics (not an inheritance example, but say you meant to provide a Compare predicate (talking C++) to std::sort providing strict weak ordering (<) on some type, but which actually provided semantics equivilent to '<=' for example). Strict-typing can be a powerful tool, where it fits, but it comes at the cost of sometimes-excess rigidity of design and still doesn't solve the subtle and difficult-to-diagnose problems that can occur where non-builtin types are used. This is why I don't see static-typing as a compelling feature for a scripting language in most use-cases.


All of that being said, it sounds as if the OP has a rather atypical use for your scripting language in mind which, from the sound of it, is to drive some sort of application almost entirely from script, and if static-typing and all that comes with it (both good and bad) is the price to be paid currently, because current dynamically-typed languages don't offer similar execution speed, then so be it. It sounds like a good choice.

Typing, whether static or dynamic, is something that needs to be understood and embraced whatever situation you find yourself in. Both have their merits and pitfalls. I think we'll see more and more applications-level programming languages move toward dynamic typing though; combined with the type of analysis and optimizations I mentioned above. The potential for less regidity, higher re-use and eschewing of low-level details is just too attractive to pass up for anything which isn't running on actual silicon.

throw table_exception("(? ???)? ? ???");

Advertisement
Quote: Original post by Ravyne
You make a good point that the bulk of a designers work is not in interfacing with the core scripting language itself, but in expressing their goals through the API that the engine exposes through the scripting language. From what I've seen of AngelScript, and mind you I'm not that up-to-date on it, it appears to be mostly limited to expressing data, control structures and logic, and doesn't make too many great strides to express concepts at a higher level than those found in the languages which have inspired it, so my charge is not that AngelScript is too hard, but that the C lineage of languages from which it has taken its inspiration is intimidating to non-programmers and also carries a not-insignificant amount of baggage and mis-steps (if not outright mistakes) that I hope AngelScript has had the good foresight to not propagate.


My goal with AngelScript is not to provide built-in higher level language features. The core library should have the basics, and then allow the application to add whatever high level language features they need through simple add-ons.

Each application will then be able to customize it to fit exactly what they need, and not carry the baggage of a lot of stuff that won't be used by the application.

Of course, I would like to provide pre-made add-ons for the most common higher level language features. But my focus remains on making the core the best it can be.

You're absolutely correct that C++ and the other languages have a lot of baggage and mistakes, and I definitely try not to reproduce those. Of course, what is a mistake or not, is often a matter of opinion.

Quote: Original post by Ravyne
Typing, whether static or dynamic, is something that needs to be understood and embraced whatever situation you find yourself in. Both have their merits and pitfalls. I think we'll see more and more applications-level programming languages move toward dynamic typing though; combined with the type of analysis and optimizations I mentioned above. The potential for less regidity, higher re-use and eschewing of low-level details is just too attractive to pass up for anything which isn't running on actual silicon.


I'm definitely not against dynamic typing. I recognize the benefits of it, and I would very much like to add support for the in AngelScript as well as an alternative to the static typing.

My decision to go with static typing back in 2003 when I started working on AngelScript was to make it easier to integrate with the host application. This is what allows the script engine to access whatever the application exposes with almost no need for any wrappers at all.

Quote: Original post by p_k
Also it seems that calling native function is quite expensive, is there somewhere speed comparison to other languages? (But this is not important to me, it can be solved by using JIT compiler)


There is a bit outdated article on codeplea.com.

On average AngelScript has similar performance of other script languages. Sometimes it is faster, sometimes it is slower. The one thing to note, is that I probably still have a lot of room for optimizations.

Please disregard the piece on the bytecode size, near the end of the article. I've addressed this with the release of 2.19.0 last month. I believe the size of the saved bytecode is now closer to what Lua has.

Quote: Original post by p_k
I'm using 64-bit Linux and when compiled with -O2 it didn't work (segfault when calling native function). I created cmake project and set -O0 for as_callfunc_xxx.cpp file. It works now. There is problem that GCC is trying to optimize such code and it's invalid after optimizations, I think that fixing this bug should be priority, maybe I can help with it. It's always game with fire when managing stack manually in C++. I'm sure that rewritting as_callfunc_x64_gcc.cpp will do the job.


I'd very much appreciate help with fix this bug.

Quote: Original post by p_k
This is okay, only the thing I wanted to advise is that enter-jit/leave-jit should be through some gateway and not per function. Personally I think that JIT compiled function should look like compiled function by C++ compiler (standard prolog/epilog, exception unwind tables).

BTW: Is there a JIT compiler (or some reference one) for AS? I didn't find any.


With the JIT interface you can go as far as you wish with the optimization. If you want to optimize just a single loop with in a function, that's OK. If you want to optimize a whole chain of function calls, then that is also OK.

So far there is only one JIT compiler for AS that I know of. It was built by quarnster for ARM processors, but it was for his own personal project and it wasn't released to the public. He was the one who helped me build the JIT interface that is currently in place.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement