Jump to content

  • Log In with Google      Sign In   
  • Create Account


ApochPiQ

Member Since 17 Jul 2002
Offline Last Active Today, 02:15 PM

Topics I've Started

Isn't "delete" so pesky to type? Wish there was a better way?

01 August 2014 - 01:09 PM

In C++, we know that memory management can be a large manual burden. Sometimes, though, it's just unavoidable, and we have to use new and delete.

A large part of the manual burden, of course, is actually typing delete, because it takes sooooo loooooong and is just annoying.


Thankfully, C++ has some special and little-known syntax to solve this headache! Suppose you have pointers (allocated via new, of course) named Foo, Bar, and Baz. All you need to do is this:

delete Foo, Bar, Baz;

Enjoy!

GDC 2014

14 March 2014 - 05:21 PM

I know there's generally mixed feelings about GDC around here, but The Time is Nigh™ and I haven't seen a thread yet, so here it is.

 

Who's going to be around this year?


Towards better error handling constructs

08 February 2014 - 05:17 PM

We all know about the eternal war between the Big Two error handling philosophies.


From Ages Immemorial we have the return-code method:

enum ReturnCode
{
    RETURN_CODE_SUCCESS,
    RETURN_CODE_BARF,
    RETURN_CODE_VOMIT,
};

ReturnCode MyFallibleFunction(int param1, const std::string& param2)
{
    // Do stuff

    // Ooops!
    return RETURN_CODE_BARF;
}
This works fine if your function only returns a result code; if it needs to have a payload as well, then you're stuck with out-parameters or other nasty hacks.


Therefore, from Slightly More Modern Times we have the exception method:

void MyFallibleFunction(int param1, const std::string& param2)
{
    // Do stuff

    // Ooops!
    throw BarfException();
}
This is nice because you can return the payload you want normally, and even attach arbitrary additional state data to the exception object itself. Unfortunately, exceptions are complicated and hard to get right, even in managed languages. Implementing exceptions is a major burden on language designers as well.


Of course there are other methods in use, such as multiple-return (return a payload in one "slot" and a success/fail code in another slot - popular in Lua, Go, etc.), discriminated-union-return (return an algebraic sum type that can carry either a success result or a failure code - popular in several functional languages), and so on. There's even the ever-mystical "continuation" method which is something like exception-style stack unwinding on steroids. (Check it out if you're not familiar with continuations, they're a damned powerful but really tricky concept that can be, at turns, very nice to have and infinitely frustrating to debug.)

A notable alternative that is popular in JavaScript (and probably other similar languages) is lambda-style handlers wherein I pass a function two lambdas, one that runs on success, and one that runs on failure. This is kind of a nice idea, but it turns into a soup of nested lambdas in complex scenarios, and gets ugly really, really fast.


I was thinking earlier about how I would implement error handling in an ideal scenario, and came up with a list of mandatory functionality I'd want involved:
  • Let me return a payload trivially - and with zero runtime overhead - in success cases
  • Allow arbitrarily rich "failure" objects/codes/etc. so I can be very precise about what went wrong
  • Complete static type safety
  • Allow arbitrary handling logic from the caller or callee when errors occur
  • Keep error processing logic close to, but not intermingled with, success-case code
Some of these are obviously easier than others.

Here's what I came up with:

entrypoint :
{
    protect
    {
        print(FallibleFunction(42, "Test"))
    }
    with task
    {
        Barf : { print("Function barfed.") }

        Vomit : string reason -> integer fallback = 0
        { print("Vomit! Falling back to 0 becuase: " ; reason) }
    }
}

FallibleFunction : integer p1, string p2 -> string ret = ""
{
    if(p1 > 100)
    {
        panic => Barf()
    }
    
    while(p1 > 20)
    {
        p1 = (panic => Vomit("Number slightly too high"))
    }

    ret = p2 ; " ... " ; cast(string, p1)
}

In this example, we set up a "fallible" function which accepts an integer and a string. We then call this function from inside a "protect" block, which is followed by a task (think actor) which can accept messages.

(NB: think of foo=>Bar() as syntax for "send the Bar message to the foo task." In this case, panic is a special task alias for the "nearest" protector task that can handle the given message.)

Inside the function, we check if the integer passed is "very large" in which case we just "barf." This is equivalent to an unrecoverable error. Then, we set up a recoverable error if the integer is "slightly" too high. In the recoverable case, we actually fire a message to the protector task and use its return value to change the parameter. This repeats until a sane value is passed in; for sake of simplicity, this can loop infinitely, but more complex and realistic handling would just obscure the example.

Finally, the function constructs a string based on its input parameters, and returns it.



I like this mechanism. It allows trivial returns of payloads in success cases, and even allows totally unguarded execution, similar to exceptions and stack unwinding, if I (as the programmer) so desire. Failure messages can pass arbitrarily rich details to the protector task. Enforcing type safety and even static error-robustness checking is possible, albeit not necessarily trivial. We see a perfect example of caller and callee interacting to correct the "vomit" condition. Last but not least, I could hypothetically use a non-inline task if I wanted to, allowing reuse of error handling logic, or separation of concerns between success and failure paths, etc.

This feels to me like the best of all possible worlds, but I'm curious if it even makes sense to anyone else, or if someone has a better idea for how to handle error situations in code. Keep in mind I'm not looking for a solution to bolt into an existing language so much as a theoretical ideal.


Thoughts?

Simple mechanisms for low-budget natural language generation

27 January 2014 - 01:32 PM

I'm hacking around on an IRC bot in my spare time, mostly as an interesting exercise in Javascript. It has some basic functionality but it just lacks that special something... so I want to teach it to talk.

 

Before we get too far into this, I should say that I'm fully aware that NLG is a massive field of research, and I'm not trying to pass any Turing tests here. I don't care if the generated "speech" even makes sense half the time; it's more for amusement than anything else.

 

My first inclination was to build a Markov model and use simple chains to construct sentences. Unfortunately, the space complexity of this is rather nasty, and the real killer is the amount of data needed to train the model adequately. I don't have a readily available corpus of plaintext to feed into the thing that suits the mood and personality I want to create.

 

The next obvious route would be to construct a Petri net for the language I want to speak. The major advantage is that this is a compact and fairly efficient way to do poor-man's NLG; the disadvantage is that hand-authoring and tuning a Petri net for nontrivial languages can be a huge time sink.

 

 

So I figured I'd poke around here and see if anyone knows of good algorithms for simple NLG that I might be able to take advantage of. I don't mind having to use a huge data set as long as the data is easily constructed and/or readily available in an easily digested format. Runtime is important since this is supposed to be a realtime conversational bot.

 

Non-goals: contextual recognition, memory, progressive refinement/learning, etc. It doesn't even have to do more than dumb keyword recognition for all I care.

 

 

Cheers!


What do you want in your development tools?

13 January 2014 - 02:55 PM

I've spent a lot of time recently thinking about things I want my programming tools to do. Some of these things are just improvements to existing concepts, and some are entire categories of functionality that don't exist in common toolkits. (To be honest, though, most of the ideas are implemented out there, just not popular or widely available.)

Fileless code organization
I'd love to stop thinking about my code in units of files. Give me a way to arbitrarily group code, maybe index it in several different ways, and I'll be much happier. I want to be able to organize on my own axes that don't always overlap with file divisions.

Semantic version control
Kind of in line with the above, I'm tired of version control that's just text-based. I want my revision history to understand that I moved a function from one module to another, or renamed a couple of variables, or whatever. Just thinking of programs as text is too limiting.

Better REPLs
The idea of a REPL (Read Eval Print Loop) is old and well-tested, but I'd like a GUI-based version. Smalltalk is the closest thing I know of to my ideal, wherein I can build arbitrarily complex data structures and run arbitrary code on them. Imagine a system where you can build entire test cases of data using a simple visual editor to lay out the data structures, and then feed that data into a module to get instant unit testing.

Better contracts
I hate the way I have to specify interfaces and contracts in most languages. More accurately, I hate the way that interfaces are everything and contracts are second-class citizens. Aspect-oriented programming is almost a step in the right direction, but most implementations are really clunky and verbose. Why can't I just say something simple, like "this function never returns null", and get automatic optimizations and sanity checks from my compiler?

Responsiveness
Visual Studio is a hog, and the other IDEs I've used are all worse. I want something slim and fast, so I can get all my coding goodness at a reasonable pace. Taking two minutes to load a project that comprises only a few dozen KB of XML on disk is just stupid.



So that's my wishlist. What's yours look like?

PARTNERS