Sign in to follow this  
nerd_boy

'when' keyword

Recommended Posts

I had this thought/idea a while ago, and was thinking about it again recently(this morning). Before/while I'm writing this post, I did/am-doing a quick Google search, and it seems the Ada language has this keyword already, although I haven't been able to find out if it was the same usage as I was thinking should be used for it. The way I was thinking involved properties, and might have the syntax of:
when <property> is <condition> <action>
So, for example, if I wished to alert the user when they try to scroll past the bounds of a scrollbar, I might have this in my constructor:
when scrollbar.Value is >scrollbar.Maximum
{
    MessageBox.Show("Scrollbar is at its limit!");
}
Implementation-wise, I'd imagine it'd 'add' the code(or, for all intents and purposes, just seem to add the code) to the Value property(without letting the code access internal/protected variables that it wouldn't normally have acces too, etc.). Then, when scrollbar.Value exceeds its Maximum(note that the actual "code" for '>scrollbar.Maximum' would be added, not the then-value of scrollbar.Maximum), it would pop-up the message box. So far, my idea only allows for the when code to exist for the entire duration that the class it is in exists, though I suppose an 'unwhen' keyword could be added... :/ So why am I tell you all this? :p Mainly cause I'd like to know if it is a good/bad idea, other than the "we don't need no more stinkin' keywords" line.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerd_boy

when scrollbar.Value is >scrollbar.Maximum
{
MessageBox.Show("Scrollbar is at its limit!");
}

The keyword is called "if":

when if (scrollbar.Value is > scrollbar.Maximum)
{
MessageBox.Show("Scrollbar is at its limit!");
}

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
The keyword is called "if":


XD

Sorry, I was just informed over IRC that I didn't make myself overly clear.
As jpetrie put it, '"when" is like injection of a delegate', whereas "if" is static.

if(scrollbar.Value>whatever) would only perform when the function/method/whatever containing was called.

when(scrollbar.Value is >whatever) would perform when scrollbar.Value is changed.

If that clears things up a bit...

Share this post


Link to post
Share on other sites
I think he wants different behavior than 'if'. He wants what is essential injection of some callback into the property setter for the given property. E.g., using a C#-like example, given:

public int P {
get {
return p;
}
set {
p = value;
}
}

then

when P > 10 {
Console.WriteLine("P > 10");
}

would change the effective behavior of P's setter to be:

set {
p = value;
if( p > 10 ) {
Console.WriteLine("P > 10");
}
}

So rather than direct execution of the conditional at that point in execution, execution of the conditional is deferred until the property in question is changed. You can, for example, simulate this in C# with interfaces supporting INotifyPropertyChanged. It's only useful to extend the properties of types you don't have control over or perhaps only want a localized, per-instance check.

It's an interesting idea, at least, but I find it a wee bit sketchy and full of a lot of edge cases that would be need to clearly defined -- what is the scope of the executing code, for example? Can it access 'this'? When exactly does it run for complex setters?

Share this post


Link to post
Share on other sites
Edit: jpetrie posted while I was posting.

Since you used MessageBox.Show() in your example, I presume you are using C#. So why don't you just put it into the "setter" of the Value property?


public int Value
{
get { ... }
set
{
if(Value > Maximum)
MessageBox.Show("Scrollbar is at its limit!");
}
}






Or am I missing something? Oh, and I also don't like the use of is. It serves no purpose, and when you have a variable with a name in plural form, it becomes odd.

[Edited by - Heptagonal on January 20, 2009 11:23:22 AM]

Share this post


Link to post
Share on other sites
I think that it could be a good idea to allow a shortcut syntax to conditional events on a property. More likely you'd want the syntax more like this:


class ScrollBar{
public auto int Maximum { ... }
public auto int Minimum { ... }
public auto int Position{
get;
set;
when (value > Maximum){ value = Maximum; }
when (value < Minimum){ value = Minimum; }
}
}


It behaves a little like certain contract designs I'd bet, but the implementation would essentially generate a delegate for the setter and hook the two when clauses into it.

I'm a little skeptical that it could be implemented well and consistently for the general case. And I think that it is less important if a language could properly allow users to define property types that are more complex than the simple get/set/value case.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
...what is the scope of the executing code, for example? Can it access 'this'


Eh, not sure how'd it be implemented, but scope would be the same as the injector. Which is to say scrollbar would be the scrollbar in the class using the when keyword, not the Scrollbar class. I'm not sure, exactly, what would be done in cases where the variable in question no longer exists. Class-wise, the when code could just be uninjected when the class is disposed/GC/whatever. But for variables who have a scope limited to a function or the inside of an if-statement, I'm not sure. >_> Perhaps a compile-time check to make sure the variable in use has a scope equivalent to that of the class?
Quote:
Original post by jpetrie
When exactly does it run for complex setters?

Tacked on at the end, in order of injection.

public int SetMe
{
set
{
me=value;
/*when usage 1*/
/*when usage 2*/
/*...*/
/*when usage n*/
}
}


Also, although C# like syntax is in use, this isn't inteded to mean I'm suggesting when for the C# language, but rather overall.

Quote:
Original post by Heptagonal
Edit: jpetrie posted while I was posting.

Since you used
MessageBox.Show()
in your example, I presume you are using C#. So why don't you just put it into the "setter" of the Value property?


I'm presuming jpetrie's post explained for you that the properties' code isn't accessible? :/ I need to explain things better...

Quote:
Original post by Heptagonal
Oh, and I also don't like the use of is. It serves no purpose, and when you have a variable with a name in plural form, it becomes odd.


The purpose it serves here is so the when keyword would know which property the condition/code is to be applied to.

when(scrollbar.Value>scrollbar.Maximum) could be used, yes, without the need for the is keyword, but then there might be confusion over something like when(scrollbar.Maximum>scrollbar.Value), where the condition/code would be injected into the scrollbar.Maximum property, since it is the first property 'found'.

Using the is keyword clears up which property the condition/code is to be applied to.

Bloody double-posting frown-upons.... ;-;

Share this post


Link to post
Share on other sites
This behavior shows up in various disparate programming models. Probably the most familiar one is SQL triggers: Every time a row is inserted or updated, do such-and-such. Make the such-and-such conditional on the row itself, or on other data, and you have the basics of you when. Key constraints offer a similar but more implicit and limited version of this.

In imperative, procedural languages, the closest thing to SQL triggers -- and therefore to when -- is events. Add a delegate listener to Scrollbar.ValueChanged that checks the condition and shows the message box, and there you are.

What's missing here, of course, is full injectability. As a user of a class, you can latch on to any events that class exports, but if you're trying to watch for a change in data that may not be followed immediately by an event firing, you are out of luck. This dovetails nicely with the hardcore encapsulation of C#, but is for crap with nimbler languages like Python.

Python, speaking of which, actually does offer this (kind of). Simply inject a setter metamethod into an object which checks the condition. It's not necessarily polite, but it works. Hell, if you do it right, these things can even be chained.

There's significant problems to injecting things like this, though. The biggie is the potential for the predicate to execute when data is in a weird state. Normally a class will clean up after itself before invoking event listeners, such that class invariants are actually invariant during the listener executions. In contrast, injecting an observer can cause the predicate to execute in the middle of a transitionally invalid object state.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerd_boy

Using the is keyword clears up which property the condition/code is to be applied to.


when scrollbar.Value is >=scrollbar.Maximum
{
scrollbar.Value = scrollbar.Maximum-1;
}
when scrollbar.Value is <=scrollbar.Minimum
{
scrollbar.Value = scrollbar.Minimum+1;
}

scrollbar.setMinimum(0);
scrollbar.setMaximum(1);
scrollbar.setValue(1);


If you want to find out more about problems that occur, try javascript, which supports such injection. Then do something like that for built-in classes like strings, and try it across different browsers, or just with non-trivial inheritance.

As soon as you try non-trivial injection, you'll see why it's either not possible, or prohibitively expensive.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
There's significant problems to injecting things like this, though. The biggie is the potential for the predicate to execute when data is in a weird state. Normally a class will clean up after itself before invoking event listeners, such that class invariants are actually invariant during the listener executions. In contrast, injecting an observer can cause the predicate to execute in the middle of a transitionally invalid object state.


Yeah, I'm not sure I've ever thought of that. A workaround comes to mind, however, if the language allowed for anonymous functions. Then, instead of injecting the code directly, either have it be when(<property>is<condition>)<function> or have the code in place of <function> be turned into an anonymous function for the class using the when keyword.

And, in this case, when it trys to call the function of 'a transitionally invalid object state', where, I assume, you wouldn't be able to call the function and would get an error/exception if you did, just ignore that specific error/exception.

Share this post


Link to post
Share on other sites
Quote:
Original post by nerd_boy
Quote:
Original post by Sneftel
There's significant problems to injecting things like this, though. The biggie is the potential for the predicate to execute when data is in a weird state. Normally a class will clean up after itself before invoking event listeners, such that class invariants are actually invariant during the listener executions. In contrast, injecting an observer can cause the predicate to execute in the middle of a transitionally invalid object state.


Yeah, I'm not sure I've ever thought of that. A workaround comes to mind, however, if the language allowed for anonymous functions. Then, instead of injecting the code directly, either have it be when(<property>is<condition>)<function> or have the code in place of <function> be turned into an anonymous function for the class using the when keyword.
I'm not sure how that's a workaround. The problem is not how the code is organized; the problem is that the predicate executes immediately upon the condition becoming true, without regard to whether any code other than the currently executing function should be allowed to see the state of the object. Have I misunderstood your proposal?

Share this post


Link to post
Share on other sites
The keyword you're looking for is if...

...in functional languages [smile] Since in a purely applicative world you have to create a new object every time you wish to apply a modification, you can put your "test on every modification" code in the constructor and be happy. For instance:


class scrollbar value maximum =
if value > scrollbar maximum then
failwith "Over the top"
else
object
val value = value
val maximum = maximum

method value = value
method maximum = maximum

method scroll_to value =
new scrollbar value maximum
end

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Quote:
Original post by nerd_boy

Using the is keyword clears up which property the condition/code is to be applied to.


when scrollbar.Value is >=scrollbar.Maximum
{
scrollbar.Value = scrollbar.Maximum-1;
}
when scrollbar.Value is <=scrollbar.Minimum
{
scrollbar.Value = scrollbar.Minimum+1;
}

scrollbar.setMinimum(0);
scrollbar.setMaximum(1);
scrollbar.setValue(1);


If you want to find out more about problems that occur, try javascript, which supports such injection. Then do something like that for built-in classes like strings, and try it across different browsers, or just with non-trivial inheritance.

As soon as you try non-trivial injection, you'll see why it's either not possible, or prohibitively expensive.


How is this any different than listening in on the ValueChanged event to change the Value given those same conditions? I believe that you'd still have the same problems.

Also, I just realized, my scrollbar.Value>scrollbar.Maximum condition will never be true... [crying]

@ToohrVyk:
I don't understand your post/code at all. O_O

Share this post


Link to post
Share on other sites
They demoed this kind of functionality in C# at Tech Ed. Perhaps it was stuff in a future version of C#. I don't recall what the syntax was though. I don't think it was a when keyword, but something else. It's the MVVM design pattern.
I think I even asked a question "How does it deal with cycles" but I can't remember what the answer was - doh!

Share this post


Link to post
Share on other sites
Quote:
Original post by nerd_boy
@ToohrVyk:
I don't understand your post/code at all. O_O


All values in pure functional languages are immutable. You generally can't modify things in place. Therefore to move a scrollbar, you need to create a new scrollbar object that represents the new state.

The roughly equivalent C++ would be:



class Scrollbar
{
int value;
int maximum;
public:
Scrollbar(int val, int max): value(val), maximum(max)
{
if(value > maximum)
{
throw std::logic_error("Value cannot exceed maximum");
}
}
int get_maximum() {return maximum;}
int get_value() {return value;}
Scrollbar scroll_to_value(int new_value)
{
return Scrollbar(new_value, maximum);
}
}



Share this post


Link to post
Share on other sites
Quote:
Original post by Valere
All values in pure functional languages are immutable. You generally can't modify things in place. Therefore to move a scrollbar, you need to create a new scrollbar object that represents the new state.


Oh...

Share this post


Link to post
Share on other sites
You might consider working with an existing GUI framework. Many of them are designed to be "event driven", which lets you basically put your if-logic in a "<property> changed" method that is called every time the value changes.

Following the C# example, it's like having this already set up for you...


public int P {
get {
return p;
}
set {
p = value;
this.p_changed();
}
}
void p_changed() {
// either you implement this yourself; or you call some method that adds
// delegates to a list, and the p_changed() implementation iterates over the
// list and calls them.
}

Share this post


Link to post
Share on other sites
when (a > b)
{
...
}

Does the code also get executed when b changes? If not, then the code is dangerously misleading. If so, and b is a complicated expression, you'll find that figuring out if b has changed wihtout evaluating it requires solving the halting problem.

Share this post


Link to post
Share on other sites
Long time ago i have had implemented a statement-behaviour system , that could do exactly that(but , its useless IMO-).

Here's how the code looks like(on top of my head , don't bite :) ):

struct StatementArg
{
StatementArg(){type=ST_UNKNOWN;cmp=false;}
StatementArg(const int stype){type=stype;cmp=false;}
StatementArg(const std::string& ss){s = ss; type = ST_STRING;cmp=false;}
StatementArg(const int si){i = si; type = ST_INT;cmp=false;}
StatementArg(const float sf){i = sf; type = ST_FLOAT;cmp=false;}
unsigned int name;
int type;

union // or boost::any ??
{
int i;
float f;
std::string s;
}
}

struct StatementArgs
{
StatementArgs(){argc=0;}
~StatementArgs(){delete args;}
unsigned int super;
int argc;
StatementArg* args;
FuncPointer* func_ptr;
FuncPointer* func_ptr_behaviour;
bool cmp;
};








void addToList(StatementArgs* arg , func_pointer,behaviour)
{
push (obj { arg&func_pointer&behaviour })
}








Handling:


StatementArgs* registerStatementArgs(Funcpointer* hook,FuncPointer* behaviour,const unsigned int top_level)
{
StatementArgs* ss = new StatementArgs;
ss->super = top_level;
addToList(arg,hook,behaviour);
return ss;
}

void removeArgs(StatementArgs* args)
{
remove arg & sub arg fields
}

StatementArgs* getStatementArgs(const unsigned int top_level)
{
find func with arg name $$$top_level
return statement
}

StatementArg* getStatementArgField(StatementArgs* super,const unsigned int name)
{
search for $name in args & return it;
}

void updateArgs()
{
for each arg
for each sub field arg
call arg->func_ptr & ->behaviour
}







Usage:


class Instructions
{
..
};

class Comparison public Instructions
{
private:
StatementArgs* args_ptr;
public:
void behaviour(StatementArg* arg)
{
args_ptr->cmp = (bool)( (args_ptr->args[0] + args_ptr->args[1]) == args_ptr->args[2]);
}
void onEq(StatementArg* arg)
{
std::cout<<"onEq called from hook manager"<<std::endl;
std::cout<<"Arg->cmp : "<<arg->cmp<<std::endl;
}
Comparison()
{
args_ptr = registerStatementArgs(onEq,hashOf("onEq"));
args_ptr->behaviour = behaviour;
//register fields
args_ptr->argc = 3;
args_ptr->args = new StatementArg[args_ptr->argc];
args_ptr->args[0].name = hashOf("num1");
args_ptr->args[1].name = hashOf("num2");
args_ptr->args[2].name = hashOf("sum");
args_ptr->args[0].i = 0;
args_ptr->args[1].i = 0;
args_ptr->args[2].i = 0;
args_ptr->args.type = ST_INT;

}
~Comparison()
{
removeArgs(args_ptr);
}
}

main()
{
Instruction* inst = new Instruction;
inst = &Comparison;


while running

int a = 0 , b = 0 , ab = 0;
get input a
get input b
get input ab
getStatementArgField(getStatementArgs(hashOf("onEq")),hashOf("num2"))->i = a;
getStatementArgField(getStatementArgs(hashOf("onEq")),hashOf("num1"))->i = b;
getStatementArgField(getStatementArgs(hashOf("onEq")),hashOf("sum"))->i =ab;

updateArgs

}







[Edited by - 3Dgonewild on January 21, 2009 4:18:38 AM]

Share this post


Link to post
Share on other sites
In Java there are some library classes for doing the when thing.
Search for:
* PropertyChangeEvent
* PropertyChangeListener
* VetoableChangeListener
* PropertyVetoException

It is possible to create an equivalent in C++ or C#(if there isn't a library class for it).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this