What's in a language that makes you like it

Started by
63 comments, last by cr88192 10 years, 1 month ago

so you can have a compiled scripting language? I thought they should be interpreted so that you can do things at runtime.

It's a bit of a definition nightmare. One definition of a script is that it's shipped and/or deployed in source form, run by (or made runable by) another tool/program/whatever that is also shipped/deployed.

There are two main usages for scripting languages however. 1) To alter/extend the behavior of a program in a simpler maner, usually without recompiling and possibly after deployment of the core product/program. In this case, the scripts would be interpreted or compiled on the fly/just in time. 2) To be able to use a simpler language for some logic, potentially suited for "less technical people". In this case, the "scripts" may be shipped/deployed in compiled form for performance or obfuscation.

So it depends on why you are using a scripting language.

Advertisement
The replies have been really insightful.
Another question. What are those syntatical features you love the most in your language (i hope it doesn't seem similar)?
puts "hello world" and cout << "hello world";.
I prefer puts.

UNREAL ENGINE 4:
Total LOC: ~3M Lines
Total Languages: ~32

--
GREAT QUOTES:
I can do ALL things through Christ - Jesus Christ
--
Logic will get you from A-Z, imagination gets you everywhere - Albert Einstein
--
The problems of the world cannot be solved by skeptics or cynics whose horizons are limited by the obvious realities. - John F. Kennedy

What are those syntatical features you love the most?
puts "hello world" and cout << "hello world";.
I prefer puts.

I personally believe (and quite a few others of my acquaintance do, too) that the stream paradigm with overloaded bit-shift operators was kind of a mistake. In the beginning, it seemed like they were so delighted about that ability to overload operators that they kind of went a little bit crazy. C++ streams make the typical C++ Hello World one of the more confusing and obtuse ones out there. I think that if C++ were started anew today, the streams with << and >> operator overloads would be done differently.

What are those syntatical features you love the most?
puts "hello world" and cout << "hello world";.
I prefer puts.


I personally believe (and quite a few others of my acquaintance do, too) that the stream paradigm with overloaded bit-shift operators was kind of a mistake. In the beginning, it seemed like they were so delighted about that ability to overload operators that they kind of went a little bit crazy. C++ streams make the typical C++ Hello World one of the more confusing and obtuse ones out there. I think that if C++ were started anew today, the streams with << and >> operator overloads would be done differently.
it really does look unnatural.

UNREAL ENGINE 4:
Total LOC: ~3M Lines
Total Languages: ~32

--
GREAT QUOTES:
I can do ALL things through Christ - Jesus Christ
--
Logic will get you from A-Z, imagination gets you everywhere - Albert Einstein
--
The problems of the world cannot be solved by skeptics or cynics whose horizons are limited by the obvious realities. - John F. Kennedy

so you can have a compiled scripting language? I thought they should be interpreted so that you can do things at runtime.


A number of scripting languages (including Lua) do offer the ability to compile to bytecode, and in fact a text chunk will be compiled on the fly when it is loaded. Then there are things like LuaJIT which is a re-implementation of the VM and a just-in-time compiler for Lua that compiles Lua script down to native machine code and can achieve a quite significant performance increase over "vanilla" Lua.

For me, I like a language if it allows me to do what I need to do without a whole bunch of hoop-jumping to do it. Lua+LuaJIT is my preferred high-level tool loadout, and C++ is my preferred low-level tool. The C++ layer provides the performance critical stuff (rendering abstraction, etc...) while the Lua layer provides the expressiveness necessary to quickly prototype and implement the high level things like enemy AI, spell and skill execution, and so forth.

bytecode, at least, is pretty much standard for scripting languages.

usually, if bytecode or similar is not used, and input text or ASTs are executed directly, the language is "impractically slow" (often around 10k or 100k times slower than native), whereas typically with a bytecode interpreter, it is usually possible to get within 50x-100x of native.

though, people have used some non-bytecode representations for interpretation with some success (typically linked lists or trees of objects), bytecode also has the advantage of being easier to store on disk and use later, and can also slightly better decouple the front-end logic from the back-end interpreter logic.

a JIT just takes things a step further, typically compiling the bytecode to native machine-code at runtime, then the native-code version is executed.

although a JIT can't usually optimize nearly as aggressively as an offline / batch compiler, it can usually get "pretty close" to native code speeds (it depends more on language and VM design and similar than the specifics of the JIT).

otherwise, a lot also comes down to language design and how the compilers and tools are implemented:

C and C++ are generally compiled directly to machine code, via offline tools;

Java and C# are generally compiled to bytecode (via offline tools), then the VM will JIT-compile them to native code;

script-languages are typically compiled to bytecode at run-time, then sometimes JIT compiled.

experimentally, it is possible to compile C and C++ dynamically (like a script language), however some things in the language design (particularly headers and the way declarations and similar work, ...) get in the way of implementing a fast compiler. also if implemented in a standards-conformant way, it is also "poor" as a scripting language, namely that it requires a lot of code to do things (making it less useful for interactive entry), and (short of internal fudging), it is far too easy to crash the host application. addressing these issues would break the standard in some fairly fundamental ways.

with Java and C# it is a lot closer, mostly boiling down to language design subtleties and awkwardness tradeoffs.

with script-languages, they are typically a lot better for small fragments and are typically very dynamic.

however, many often skimp out on lots of things needed for more serious coding or for general scalability, so one is left with a language often lacking much good support for being able to use libraries, and turning into an awful mess as code moves past a few thousand lines (this is where more traditional "compiled language" features tend to do well).

a compromise is possible though.

if you have a language that can both be batch compiled, as well as loaded as script-code fragments and dynamically compiled at run-time, supports features to be usable from small code fragments (as can be written interactively), supports both static and dynamic typing, supports things like packages/namespaces and classes, can more easily use code from C libraries (*), ... then things can be a little nicer.

*: though in my VM, this requires use of batch tools to process headers and, in some cases, to generate stub-code (usually for exporting stuff to C land).

usually this can be combined with any native code into the form of a DLL. usually for imports from C land, it isn't very fussy (it imports pretty much everything from the seen headers which are reachable via DLL imports). though, some things in C-land have been black-listed (mostly for security reasons).

IME, static types and classes, while not particularly advantageous for small code fragments, become a fair bit more useful as code gets larger (for organization, and for things like the compiler helpfully informing the programmer that they messed up their argument list or similar). they also have an advantage of being easier to optimize. though, also having both static and dynamic types can be fairly useful (dynamic types can be fit into a static type system by seeing them as a type-of-type, so in many practical regards, seeing static and dynamic types as opposed is a false dichotomy, and can offer an advantage for cases where, in fact, one is actually dealing with multiple types at run-time).

however, to support both use-cases, a language tends to require both sets of feature-sets, typically resulting in something a little bigger and more complex than either would be on its own (a scripting language with the full feature-set of a traditional compiled language thrown on, or seen the other way, a traditional compiled language having to deal with a lot of the added complexities of supporting dynamic features).

for example, to support both the feature-sets of C and JavaScript, the actual compiler and VM ends up a bit more complicated than either a C or JavaScript compiler or VM would be on their own, and a superset of C, JavaScript, and C#, adds that much more. though, on the positive side, the language can do a little more nifty stuff... (and complexity isn't usually as big of a deal in-practice as it is in-concept).

This topic is closed to new replies.

Advertisement