Weblogs Forum
Call-Out-The-Back

25 replies on 2 pages. Most recent reply: Mar 10, 2006 10:32 AM by piglet

 Previous Topic Next Topic
 Flat View: This topic has 25 replies on 2 pages [ 1 2 | » ]
 Christopher Diggins Posts: 1215 Nickname: cdiggins Registered: Feb, 2004
Call-Out-The-Back (View in Weblogs)
Posted: Feb 13, 2006 7:09 AM
Summary
Part of the problem of not specifying what an object depends on, is that its dependencies can violate its invariants. This results in a program that Brian Shearing calls the "Calls-Out-The-Back" problem.
The following was lifted from the notes for Peter Grogono's keynote presentation at CUSEC 2006. This extends the initial thoughs presented on my earlier blog post The Backside of an Interface.
Consider the following class Foo.
```class Foo
{
private int x = 0
private int y = 0
invariant y = 2× x
public void f()
{
x += 1
y += 2
}
public void g()
{
x *= 3
y *= 3
}
}
```
It has an invariant — you all know what an invariant is, of cousre — anyway, this invariant says that y is always twice x. The initial values, x = y = 0, respect the invariant. Both functions, f and g, maintain the invariant. Everything’s fine.

Now let’s give it a variable b and call b’s function h. Note that this does not change the (so- called) interface of Foo, because the new variable is private and the call is an implementation secret of Foo.f .

```class Foo
{
private int x = 0
private int y = 0
private Bar b
invariant y = 2 * x

public void f()
{
x += 1
b.h()
y += 2
}
public void g()
{
x *= 3
y *= 3
}
}
```
Now look at class Bar. It’s method h calls Foo’s function g.
```class Bar
{
private Foo f
public void h()
{
f.g();
}
}
```
This has unexpected consequences for Foo. Think of the interface as being the top of the box. The damage is done by the thread of control coming out of the bottom of the box — nothing to do with the “interface”.Here is the sequence of assignments that take place and the resulting values:
```x = 0 0
y = 0 0
x += 1 1
x *= 3 3
y *= 3 0
y += 2 2
```
The invariant now says 2 = 2 ×3. Oops! The call b.h() in class Foo is an important part of its behaviour — and therefore must be considered as part of its interface. Note how Foo has lost control of its “private” internals. As a technical aside, note also that if Foo was a monitor allowing only one method to be executed at a time, this program would deadlock.

I’ve presented this as an example of the meaning of interface. But you should note that it is really quite a serious problem: objects have no control over their private data. This is a consequence of the fact that objects can invoke functions in other objects.

 James Watson Posts: 2024 Nickname: watson Registered: Sep, 2005
Re: Call-Out-The-Back Posted: Feb 13, 2006 8:11 AM
Can you explain how you would solve this with a 'back interface' or whatever you want to call it? There are thousands of programming errors we could list. I don't really see the point of talking about this unless you have a solution.

 James Watson Posts: 2024 Nickname: watson Registered: Sep, 2005
Re: Call-Out-The-Back Posted: Feb 13, 2006 8:18 AM
Also, this is a perfect example of what I was getting at in the other thread in a recent post. The problem you describe here is rooted in the bidirectionality of the interfaces. If the interfaces were layered in a one-directional way the problem would not exist. Also, even if just the instances were not bi-directionally linked, the problem goes away.

 Harrison Ainsworth Posts: 57 Nickname: hxa7241 Registered: Apr, 2005
huh? Posted: Feb 13, 2006 9:26 AM

It would need to be given a reference to them, by the owning Foo. In which case the Foo has deliberately surrendered control. (well, in C++, Java, or Ruby...)

The Foo in Bar is another instance.

 Christopher Diggins Posts: 1215 Nickname: cdiggins Registered: Feb, 2004
Re: huh? Posted: Feb 13, 2006 2:15 PM
>
> It would need to be given a reference to them, by the
> owning Foo. In which case the Foo has deliberately
> surrendered control. (well, in C++, Java, or Ruby...)

Or it could have gotten it somewhere else. How it gets the reference is irrelavent. The point is that it is representative of a problem of how a back-door call can corrupt the object.

 Maxim Noah Khailo Posts: 25 Nickname: mempko Registered: Nov, 2004
Re: huh? Posted: Feb 13, 2006 3:36 PM
> >
> > It would need to be given a reference to them, by the
> > owning Foo. In which case the Foo has deliberately
> > surrendered control. (well, in C++, Java, or Ruby...)
>
> Or it could have gotten it somewhere else. How it gets the
> reference is irrelavent. The point is that it is
> representative of a problem of how a back-door call can
> corrupt the object.

Well, there is one problem with your example. You explicitly gave control over to the Bar object at that point. Because explicit control is given over to Bar::h() then the function f() cannot be guaranteed to keep the invariant unless you explicitly have checked the code for Bar::h(). Now it is clear you wanted to created a "backdoor" to your class. This problem is easy to solve during debugging by having an assert at the end of f(), or some other kind of error checking. Now the question is do you want your language heron to take care of this automatically? I am guessing that you do. In that case because it seems you have an explicit "invariant" type modifier, i am guessing heron automagically puts those asserts in all functions that access or modify the variable y. If so, then this problem can be detected at runtime. The tougher problem is doing this kind of checking at compiletime. Currently as a C++ programmer, you would have to check this by hand....like knowing that if you give control over to Bar, then bar can mess things up.

Now, I suppose heron can create a callgraph during compiletime and check if Bar calls back to a function that modifies a variable that there is an invariant for. If so give a warning to let the programmer know. The obvious problem with this is that you may not be able to create a callgraph to a library function...or runtime callbacks. In which case the automagic asserts should help find the problem. there are probably tons of other solutions too :)

 James Watson Posts: 2024 Nickname: watson Registered: Sep, 2005
Re: huh? Posted: Feb 14, 2006 6:26 AM
That there is a backdoor isn't the problem. It's that the call to b.h() is made in the middle of a critical section of code with respect to the invariant. If the call were made at the end of the method, it would not cause a problem. What I want to see is an real example where interrupting an 'atomic set' of operations is unavoidable. I have some doubt that there is such an unavoidable situation but I won't be that surprised if someone can show one.

 Kresimir Cosic Posts: 6 Nickname: kreso Registered: Jan, 2006
Re: Call-Out-The-Back Posted: Feb 14, 2006 7:37 AM
This is a bad example for your case. It is an example of how a programmer can seriously mess up, and then blame it on the language.

The whole problem is that function f() doesn't really respect the invariant, and its obvious. Because:

x+=1
//now the class isn't in the well defined state anymore

b.h() //huh? Transmitting control to another class while
//leaving class Foo in forbidden state.. obviously an error

The problem of your example isn't in a back-interface. The problem is that the programmer of class foo broke his own contract.

 Maxim Noah Khailo Posts: 25 Nickname: mempko Registered: Nov, 2004
Re: Call-Out-The-Back Posted: Feb 14, 2006 3:21 PM
> This is a bad example for your case. It is an example of
> how a programmer can seriously mess up, and then blame it
> on the language.
>
> The whole problem is that function f() doesn't really
> respect the invariant, and its obvious. Because:
>
> x+=1
> //now the class isn't in the well defined state anymore
>
> b.h() //huh? Transmitting control to another class while
>
> //leaving class Foo in forbidden state.. obviously
> viously an error
>
> The problem of your example isn't in a back-interface. The
> problem is that the programmer of class foo broke his own
> contract.

Exactly :) As I mentioned above, there might be ways the language can "help" the programmer realize this, but essentially, yes, the programmer diliberatly left it class Foo in a bad state. I agree also with james that an example where an operation on Foo is unavoidably interrupted would be better.

 Calvin Mathew Spealman Posts: 13 Nickname: ironfroggy Registered: Aug, 2005
Re: Call-Out-The-Back Posted: Feb 17, 2006 4:35 PM
This seems to have nothing but negative commentary, all either not understanding the problem or believing it to be a bad example of the problem. Everyone needs to understand this is an example, not a real-world case. In any real-world case where this would come up and be difficult to spot, there would be a much more complicated set of invarients and updating all of the properties to satisfy those invarients would be equally or more complicated, and what do we all know is the number one way to simplify complicated code? We break it down into functions. Some may say, "Make those functions private methods.", but I will just say, "They may be better to be public methods of the properties themselves."

So, scale this example up to a real-world case that would be difficult to keep under control in some circumstances. You need to keep the invarients satisfied, but sometimes that process requires you to make this kind of dangerous move, so yes, you do need a way to protect yourself.

So, Chris, what is the solution, if you are so quick to tell us all the problem?

 Cleo Saulnier Posts: 77 Nickname: vorlath Registered: Dec, 2005
Re: Call-Out-The-Back Posted: Feb 20, 2006 7:58 PM
From what I can tell, this specific problem is that even if you pass an interface to an object, there is no guarantee or restriction on what the interface is allowed to do concerning other objects. I see a bigger problem of coupling. What is the implementation of this interface affecting? Can I really remove this interface implementation and safely replace it with another?

The problem isn't that the programmer made a mistake in the implementation of the interface (or the order of calls). It's that the object requiring the interface cannot be assured that when it calls this interface, that the interface doesn't do something malicious or erroneous, thus making the object itself incorrect by proxy. There should be a way to safeguard against this. Otherwise, errors can be introduced in an object that is technically correct.

The example given in this blog entry is simplistic, but in any large system, and if you are a proponent of GC, then there is a likely chance that there are far too many objects to be tracked in order to make sure this situation is avoided. The answer to this problem is obvious. But it requires tracking of resources. That's why I've always been against GC. It leads to too many coupling problems in large scale systems. Not to mention a maintenance nightmare. But because it goes against GC, I'm expecting that this notion of calling out the back will be dismissed vehemently.

 James Watson Posts: 2024 Nickname: watson Registered: Sep, 2005
Re: Call-Out-The-Back Posted: Feb 21, 2006 7:00 AM
> The example given in this blog entry is simplistic, but in
> any large system, and if you are a proponent of GC, then
> there is a likely chance that there are far too many
> objects to be tracked in order to make sure this situation
> is avoided.

I use GC all the time and this is not my experience at all. The situation is avoided by proper design.

> The answer to this problem is obvious. But
> it requires tracking of resources. That's why I've always
> been against GC. It leads to too many coupling problems
> in large scale systems. Not to mention a maintenance
> nightmare.

How does GC cause coupling problems?

 Vincent O'Sullivan Posts: 724 Nickname: vincent Registered: Nov, 2002
Re: Call-Out-The-Back Posted: Feb 22, 2006 7:18 AM
> From what I can tell, this specific problem is that even
> if you pass an interface to an object, there is no
> guarantee or restriction on what the interface is allowed
> to do concerning other objects.

That's quite right. An interface doesn't describe implementation, in fact its purpose is specifically to mask implementation. Therefore you should not be surprised if you pass control of an object through an interface and find that it has been changed when you get it back. As James said above, it is bad design.

 James Watson Posts: 2024 Nickname: watson Registered: Sep, 2005
Re: Call-Out-The-Back Posted: Feb 23, 2006 7:13 AM
> > The answer to this problem is obvious. But
> > it requires tracking of resources. That's why I've
> always
> > been against GC. It leads to too many coupling
> problems
> > in large scale systems. Not to mention a maintenance
> > nightmare.
>
> How does GC cause coupling problems?

I just want to be clear that if you have a cohesive argument for this I'd love to see it. I am keeping my mind wide open. One of the reasons I'm curious is that I see lots of coupling but I'm not convinced GC is the cause. I always figured the cause was clowntown development.

 Cleo Saulnier Posts: 77 Nickname: vorlath Registered: Dec, 2005
Re: Call-Out-The-Back Posted: Feb 27, 2006 8:37 PM
No, you're right. It's caused by "clowntown development". Nice term BTW. But GC tends to make this kind of clowntown development easier because you don't have to keep track of your data (as much). Whenever the last reference goes null or out of scope, then the data will remove itself (hopefully). I just think if there was more enforcement and planning on what data these functions can use and what objects they can create and use, then there would be less problems. But this is the whole reason behind GC. To not have to track your data. This may be a personal opinion, but I find that GC and the calling out the back issue (along with normal interfaces to some extent) are diametrically opposed. One is implicit, the other is explicit.

I am not saying removing GC is the answer either because C++ has the same problem. The solution is to have a back interface so that the application can let it only use functionality that is considered "safe", whatever that may mean in your project. I have seen no language that supports this of yet, but I have not seen all languages. I doubt it would be popular because you would need the IDE or some tool to help you out and unless there is some kind of code hiding feature, I think it would be messy and cumbersome.

Imagine that you're implementing an interface and you can't use the "new" keyword or call any functions unless they are part of the standard library (considered safe) or from another interface or supplied by the application? Note too that the GC is irrelevant because all your resources must be externally and explicitely supplied to make sure you don't cause havoc and use safe functionality. No way that this would fly now that GC is so popular. Manual management of resources is not "IN" anymore. But there's no doubt that unbridled method calls and use of "new" leads to coupling.

Not sure if I conveyed my argument very well, but hopefully you got the gist of it.

 Flat View: This topic has 25 replies on 2 pages [ 1  2 | » ]
 Previous Topic Next Topic