7

For fun I was thinking about how a programming paradigm could differ from OOP and came up with this concept. I don't have a strong foundation in computer science so it might be common place without me knowing it (more likely it's just a stupid idea :)

I apologize in advance for this somewhat rambling question, anyways here goes:

In normal OOP methods and classes are variant only upon parameters, meaning if two different classes/methods call the same method they get the same output.

My, perhaps crazy idea, is that the calling method and class could be an "invisible" part of it's signature and the response could vary depending on who call's an method.

Say that we have a Window object with a Break() method, now anyone (who has access) could call this method on Window with the same result.

Now say that we have two different objects, Hammer and SledgeHammer. If Break need to produce different results based on these we'd pass them as parameters Break(IBluntObject bluntObject)

With a mutating programming language (mpl) the operating objects on the method would be visible to the Break Method without begin explicitly defined and it could adopt itself based on them). So if SledgeHammer calls Window.Break() it would generate vastly different results than if Hammer did so.

If classes are black boxes then mutating classes are black boxes that knows who's (trying) to push it's buttons and can adapt their behavior accordingly.

You could also have different permission sets on methods depending who's calling them rather than having absolute permissions like public and private.

Does this have any advantage over OOP? Or perhaps I should say, would it add anything to it since you should be able to simply add this aspect to methods (just give access to a CallingMethod and CallingClass variable in context)

I'm not sure, might be to hard to wrap one's head around, it would be kinda interesting to have classes that adopted themselves to who uses them though. Still it's an interesting concept, what do you think, is it viable?

Here's some potential dummy code from a game where a player has is damaged by something. In normal OOP most things would instead be passed as parameters to the method whereas here Damage "pulls" the properties it uses. Different? yes, better? perhaps not :)

Class Player
{
    [AccessableBy:Terrain,Player]
    void Damage
    {
        if (#CallingClass has property HitPoints)
        {
            this.health -= #CallingClass.HitPoints;
        }

        if (this.health < 0 && #CallingClass is Terrain)
        {
            ShowMessage("was killed by the environment");
        }
        else if (health < 0 && #CallingClass is Player &&  #CallingMethod is RocketLauncher)
        {
            ShowMessage("was killed with a rocketlauncher by player" + #CallingClass.PlayerName);
        }

    }
}

To reduce if-else statements you could have method overrides based on caller methods and classes

8
  • 2
    How is this so different from OOP where one can have classes inherit various methods or override them? As an example, consider classes for rectangle and square where the latter overrides the area computation by being just squaring the input of a side length rather than doing a length times width computation. I'll grant that the permissions may be interesting except that most systems will have separate parts where security is handled in a rather configurable fashion as this tends to be customized to some extent so I question how useful is that for a distributed system.
    – JB King
    Jan 11, 2011 at 21:26
  • 4
    Don't virtual functions and inheritance essential do exactly this?
    – Pemdas
    Jan 11, 2011 at 21:27
  • The difference is that methods could return different result depending on which class and method calls them. Of course you can get this behavior pretty much with parameters and polymorphism but it would have to be explicitly declared. What you're really doing is moving logic and responsibility from the caller to callee'. Say that you have an Encryption Class, it could encrypt data differently depending on the needs of the caller, kinda lika a built-in factory pattern.
    – Homde
    Jan 11, 2011 at 21:34
  • 11
    Is Window 'object' supposed to know all possible 'objects' that might want to break() it?
    – Mchl
    Jan 11, 2011 at 21:37
  • 2
    @JB King: the fact that it can be easily implemented in OOP or functional programming doesn't by itself make it useless. Creating a non-trivial library with this concept could be interesting. OTOH, I do think that this would only help in making code harder to read and create tighter binding between modules; both highly undesirable features.
    – Javier
    Jan 12, 2011 at 1:38

9 Answers 9

21

Let me see if I understand what you're getting at.

In traditional OOP languages like C++ or C#, the action of a method depends on the runtime type of the receiver:

Window w1 = new GlassWindow();
Window w2 = new PlexiglassWindow();
w1.Break(new Brick());
w2.Break(new Brick());

Which method is actually invoked depends on the runtime type, not the compile time type, of the receiver, provided that Break is "virtual".

Languages which have this property are called "single virtual dispatch" languages.

Your proposal is that the action of Break depend also upon the runtime type of the argument. Suppose Break takes an Object:

w1.Break(new Hammer());
w1.Break(new Pillow());
w2.Break(new Hammer());
w2.Break(new Pillow());

and now perhaps four different things happen depending on the runtime types.

This sort of double dispatch operation is very common in things like games, where you want to have different logic for every possible kind of collision: player with laser, laser with laser, laser with player, player with wall, laser with wall...

Languages that have this property are called "double dispatch" languages; languages that can do more than double dispatch are said to be "multiple dispatch".

This is a pretty well-studied area; do a web search on "visitor pattern" to learn more about simulating double dispatch in a single dispatch language.

11
  • Eric, that's not entirely what i mean. It's more like, say that Brick has some method calling Window Break: SomeBrickMethod(){window.Break();} Window's Break Method has two context properties CallingMethod and CallingClass so it's Break method can use that information for conditional purposes or pulling some property out of the calling class/interface, like void Break(){if (Break.CallingMethod is SomeBrickMethod) force = CallingClass.ForceImpact)}
    – Homde
    Jan 11, 2011 at 22:19
  • So CallingMethod and CallingClass are always implicitly declared and available for any method and class
    – Homde
    Jan 11, 2011 at 22:25
  • 4
    @MattiasK: I don't understand what the difference is between Hammer calling Break and Break "magically" knowing that Hammer called it, and Hammer passing an instance of itself to Break. Aside from possibly details of what the syntax looks like, how do the two scenarios differ? Jan 11, 2011 at 22:31
  • I'm not sure myself :) but if methods/classes always implicitly know who calls them that could open up for some higher abstraction/flexibility and interesting possibilities. You wouldn't have as strict method signatures for once perhaps making versioning/refactoring easier. You could go even further and classes knowing what class they're contained in etc. Factory/Visitor patterns etc take care of most of these scenarios but perhaps this would be simpler, perhaps not :)
    – Homde
    Jan 11, 2011 at 22:38
  • 1
    @Eric, I don't think that the scenarios do differ from a pure CS perspective... but having "magical" syntax for something can make all the difference in the world from a pragmatic programming perspective. Jan 11, 2011 at 23:28
3

This sounds pretty much like what S4 is doing in R : defining a generic method and then dispatching to a method based on the signature of the arguments, i.e. :

setGeneric("sum", function(x,y) standardGeneric("sum")) 

# method for numeric object with a numeric argument
setMethod("sum", 
          signature=c("numeric","numeric"), 
          function {
             return(x+y)
})

# method for a numeric object with a character argument
setMethod("sum", 
          signature=c("numeric","character"), 
          function {
             return(paste(x,y))
})

# method for a numeric object with all the rest
setMethod("sum",
          signature=c("numeric","ANY"), 
          function {
             return(x)
})

Or I must have misunderstood you completely. In this code the function "sum" will match the given arguments (what you call the caller (first argument) and the callee (second argument) with the signature of the functions. If it can't match, it will match the one where the signature says "ANY".

PS : this is a trivial example, obviously

4
  • 2
    +1: I think the OP should try R or Common Lisp, which has a similar facility for generic methods. Jan 11, 2011 at 21:57
  • @Larry: good point about Common Lisp!
    – Joris Meys
    Jan 11, 2011 at 22:29
  • R, Common Lisp, Dylan, Clojure ... Jan 12, 2011 at 10:08
  • The question was about the type of the calling object, not the type of any parameters passed in the call. Sep 21, 2020 at 10:13
3

You might want to look into Subject-Oriented Programming, as e.g. implemented in the Us Programming Language (by the same people who also did a very nice implementation of Object-Oriented Programming in the Self Programming Language).

In Subject-Oriented Programming, the shape of an object is subjective from the point of view of its caller. I.e. to every caller the object looks different.

This idea was even more generalized in the idea of Context-Oriented Programming in the Korz Programming Language, which has been presented a couple of times this year.

2

One of main rules in life is not to add extra complexity unless it's needed. The caller in OOP can always pass some parameter that would tell the callee, how exactly the callee must behave. What you want to do is just add an implicit parameter (class/method signature). And what the purpose is?

If some method should react on what the caller is, then just pass the caller's class name / type / whatever explicitly and that's all. With good RTTI this can be done in a handy way - you pass a reference to the caller's object to a callee and callee inspects the type info of the caller object.

2
  • I guess the main concept I thought was interesting is a shift to methods and classes know who's using them and could be "adaptive" using those facts. Not having to declare explicit parameters could make code more flexible, esp if you combine it with ducktyping. I'm a bit unsure of whether it would work practically though :)
    – Homde
    Jan 11, 2011 at 22:51
  • 1
    @MattiasK - most callers are written long after the code they call. What use is it for my library to know specifically that it's called by Fred if I never heard of Fred, because Fred won't exist for another 10 years? Adapting to context is fine, but not if you can't understand the context. Run-time dispatch (multiple included) is fine. The parameter provides the context in a way that is explicit enough - the run-time type is as explicit as the value, both hidden behind the same identifier/expression/whatever.
    – user8709
    Jan 12, 2011 at 4:21
1

I think what you are suggesting completely breaks the concept of abstraction all together. A function should not have logic based on what function or object called it. The is an implicit dependency there that would be a maintenance nightmare.

1

You can already do this (i.e. finding out who the calling class/method is) in any JVM language by looking at the stack trace. You should have a look at the documentation for the method "getStackTrace" in the Thread class. What you want can be implemented in just a few lines.

0

Sounds like extension methods.

Except extension methods can only live on static classes. You just want the same idea (a this parameter modifier) for any method.

2
  • 1
    Not really, as I said the main difference is that the called method knows who's calling it, and can react accordingly. You don't know that with extensions methods
    – Homde
    Jan 11, 2011 at 22:17
  • somewhere you still have to define what the reaction is.
    – Pemdas
    Jan 12, 2011 at 4:29
0

Your idea sounds similar to:

It turns out that you may not even need implicit parameters for what you're trying to do.

0
-2

This sounds a lot like typeclasses, or, as @Ken Bloom points out, Scala's implicit parameters (which are basically Scala's object-oriented interpretation of typeclasses).

Not the answer you're looking for? Browse other questions tagged or ask your own question.