Faster, smaller, safer

Here is a summary of recent changes for DWScript, available in the SVN version:

  • faster: compilation is now about 30% faster in situations like that benchmark, thanks to a few bug fixes (typechecks were performed multiple times) and a couple tokenizer enhancements.
  • smaller: reduced memory usage for compiled scripts (about 15% in the infamous benchmark, which translates in an execution speedup of around 5% once a few hundred lines are involved).
  • safer: fixed an old issue with object reference cycles, which weren’t covered by the reference counting and thus could be leaked.
  • basic support for “for..in”, at the moment limited to the case of enumerations (for <element> in <enumeration>).
  • fixed compile error source locations for some issues, plus various minor fixes and enhancements.

12 thoughts on “Faster, smaller, safer

  1. Very nice. But for all your improvements, you’re missing a feature. I’d like to switch over from PascalScript to DWS–you’ve got a lot better feature set and you’re actually committed to improving the product, instead of the long litany of “we have no plans to support X” I keep hearing from RemObjects–but you don’t have GOTOs.

    I know it’s considered bad practice, but I need goto support. I’ve got to be able to run legacy code translated from a system that had minimal support for structured programming. There are only four flow of control statements. In Pascal we’d know them as “while true do,” “break,” (the only way out of the infinite loop,) “exit,” and “label/goto,” and I need to be able to correctly emulate all four.

    PascalScript has goto support but doesn’t quite get it right. See http://code.remobjects.com/p/pascalscript/issues/14/ for an error I found in it more than 2 years ago that no one’s bothered to fix. If you could find some way to implement it correctly I’d be very grateful.

  2. The expression tree of DWS doesn’t lend itself to goto execution, at least not without a lot of code and compromising execution performance of regular code.
    There is afaict only one case where it could be supported in a practical fashion: if jumping only within the same block, ie not jumping outside of a block or control structure, and not jumping into one. That wouldn’t be very useful though, as f.i. the then of a if has its own internal block… so your goto would have to be non-conditional.
    Depending on what your code look likes, it might ne more practical to morph the original code into modern structures.

  3. @Eric
    Yeah, that’s not practical. It’s not my code, and the system it’s designed for is not very amenable to structured programming. I don’t think I’d be able to come up with an algorithm to refactor the goto-containing code into better-structured code without altering the script semantics.

    The error I posted a link to breaks the PascalScript compiler for the same reason you gave: the goto in the example doesn’t fit well into a tree structure.

  4. I’m sorry but I have to agree with Mason, some think that goto’s are a bad practice, but I love using labels and goto’s — and really use them a lot.
    Having goto support is really a must if not now, but surly in the future… disagree if you like too, everyone has opinions, but DWS’s source is small, it can be “easily” modified to support goto’s.

  5. @Dorin, as far as I know, and as Eric wrote above, the DWS source size has nothing to do with “easy” goto implementation. By design, the execution tree of DWS is stack-based, so goto is not an option here.
    The DWS execution is performed by classes methods calling themselves (see all the Execute methods), putting some parameters on the CPU stack between each method call. In practice, this is efficient, and this design allows DWS to be easy to maintain.
    But a “goto” will have to go from one stack position to another, which is difficult to implement. Some exception-based mechanism could be used, but it definitively won’t be good about performance, and in some case (depending of the goto scope) it won’t work at all.

    In my code, the only time I use goto is when performance really matters. In this case, my Delphi code structure maps the asm code generated by the compiler. For instance, I use it into some parser algorithm, because a goto could be sometimes much efficient than other solutions.
    IMHO “goto” have to be avoided in most places, especially in a script. Use rather modern structures using sub-functions then exit, or while/repeat then break.

  6. Yes, that’s the issue. Implementing a goto would either be of wicked complexity with lot of code to bypass the stack contexts, or be very limited with lots of performance implications, and given that the functionality isn’t that desirable as Arnaud said, it isn’t worth the trouble IMHO.
    That said, I’ll likely be adding some ways to allow for custom parsing, and so “plugin” language extensions, it isn’t targeted at supporting gotos, but as far as parsing goes, you could use it to parse gotos/labels (implementing them would be another story as said above, but if you really really want to try for gotos in a specific case…)

  7. One other thing I’ve noticed: DWS seems to want all the scripts to be free-floating. It doesn’t understand source file structure keywords like “unit”, “program”, “end.”, “interface” and “implementation”.

    You have support for units, but this only seems to cover external units that link to Delphi code. Do you have any plans to implement script units in DWS? This would make DWS a lot more useful.

  8. That part of DWS is still essentially in the state it was in DWS2, I have never really looked into it nor needed to at that point.
    I have some plans to introduce explicit “uses”, but mostly targeted at external units, and to handle cases when there is an over-abundance of external units (we’re reaching that point here).
    There aren’t plans at the moment to introduce full-blown units, but maybe something in between could be possible (currently, when there are needs for libraries, people are using includes here)

    Keep in mind that this is a scripting language, and if DWS + external units can offer an edge over Delphi (greater flexibility, similar ballpark performance), the rationale for having many complex libraries written in DWS is somewhat lower, not only because of performance issues, but because the code complexity can negate the advantages of using a scripting language, so you may as well use Delphi directly.

  9. @Eric
    My use case is one where I can’t just use Delphi directly. I’ve got a game engine where each level has its own set of scripts specific to that level, plus there’s a set of “global” scripts that can be called from any map. Depending on the complexity level of the game, this global block can be huge: thousands of individual scripts, some simple, some quite complex.

    I’d really prefer to not have to use $I and recompile something that big for every single map. It seems like it shouldn’t increase complexity too much to create units. You’ve already got a way to use TProgramInfo to find functions by name and call them. That means that each unit could be compiled to a TdwsProgram and basically treated like a .DCU, with main scripts or other units linking to it and calling the routines it contains.

  10. Yes, that’s what I meant by something in between a full-blown unit and an include, ie. such a unit wouldn’t have a differentiation between interface and implementation.
    Full blown units, means adding that distinction, plus initialization/finalization. And induced limitation however would be that you couldn’t have circular dependencies between such “units”.

Comments are closed.