Re: [trygve] Problem with playing too many roles in nested contexts (#10)

70 views
Skip to first unread message

James O Coplien

unread,
Dec 18, 2015, 6:33:11 AM12/18/15
to jcoplien/trygve, object-co...@googlegroups.com

Den 18/12/2015 kl. 03.21 skrev Andreas <notifi...@github.com>:

I was surprised this wasn't allowed? Isn't the outer Context put on hold while the other one executes?

When I implemented this, I knew that it would raise eyebrows and that it would be difficult to describe. But I think that it is exactly the right behaviour.

Think of it this way: what if CleanTable modified some state of Person on which WaitTable depended? Let’s say that in CleanTable, the clean method put an apron in the waiter. That isn’t very becoming of a waiter who is also playing the role of Waiter in the WaitTable Context. It becomes a surprise, a side-effect on the object that I am unable to reason about from within the WaitTable Context.

It’s of course O.K. if the second Context doesn’t do anything that would disable the Role-player from carrying out its Role in the current Context. If the second Context doesn’t modify the state of the Role-player then it can be guaranteed to be safe. And that’s why Stage Props exist.

Right now I think the environment just barks at you if it finds an object playing multiple Roles — I think it nonetheless goes ahead and does what you ask. Maybe there should be a language feature that enables you to tell the compiler “I know what I’m doing” so that a given object is allowed to play multiple Roles concurrently. I’m not sure. It takes out out of the realm of simplicity. But I’m not sure that is a property of the object, or if one or the other Role signifies the other Roles that the object may concurrently play. It may be different for different Role-players. I’m interested in your ideas on this. I’m copying the list to get broader feedback.

I see that earlier you posted the bug to the object-composition group that elicited the “Object of type Note playing too many roles, including LowNote” error, even though the Role-player was only playing Stage Props. I believe that has been fixed.

By the way, you should be very proud of your code. It’s nice to see the language features actually used, and used so insightedly. You know you’re the first person in the world who’s actually doing this in a language designed exactly for this purpose! We should get some of your code up on fulloo.info — maybe the chord identifier code once it’s tidied up.

I have on my list to chase down a whole bunch of other “little” bugs you’ve found — like the problems with logical negation, another problem you mentioned with using integers (so you were forced to use floats), a problem with rich boolean expressions in assert arguments, etc. I expect it will take about two or three months of continued effort to get through the alpha release stage and get to the point where we can honestly call this a beta. At that point I hope people start digging into the code and sending me pull requests for their branches (hint, hint, Matt…)

As for right now, I’m happy to have people add test examples. The more, the merrier. I’ll delete them if I find them totally unusable but almost every new piece of code tortures the environment in a new way. To add a test, just put it in the tests/ folder with a .k suffix. Then go into info.fulloo.trygve.editor and it to the list of test files in TestRunner.java. Please do this only for examples that work. Bug examples should be sent directly to me.

(By the way, when you send me code via Email, all the periods are elided ;-) I can usually figure them out from context, and I’ve re-inserted them below.)

class Person {
    public Person(String name) {
        name_ = name;
    }

    public String name() const {
        return name_;
    }

    private String name_;
}

context CleanTable {
    role Waiter {} requires {
        String name() const;
    }

    // Nice duck typing feature :)
    public CleanTable(Waiter person) {
        Waiter = person;
    }

    public void clean() {
        System.out.println(Waiter.name() + " is cleaning the table");
    }
}

context WaitTable {
    role Waiter {
        public void waitForGuestsToFinish() {
            new CleanTable(this).clean();
        }
    } requires {
        String name() const;
    }

    public WaitTable(Person person) {
        Waiter = person;
    }

    public void start() {
        Waiter.waitForGuestsToFinish();
    }
}

{
    Person p = new Person("Jeeves");
    new WaitTable(p).start();
}

Full output:

___________________________________________________________
Object of type Person playing too many roles, including Waiter
    In Context WaitTable: Waiter
    In Context CleanTable: Waiter
Jeeves is cleaning the table

Rune Funch Søltoft

unread,
Dec 18, 2015, 7:49:18 AM12/18/15
to object-co...@googlegroups.com


> Den 18. dec. 2015 kl. 12.33 skrev James O Coplien <co...@gertrudandcope.com>:
>
> Maybe there should be a language feature that enables you to tell the compiler “I know what I’m doing” so that a given object is allowed to play multiple Roles concurrently

If so maybe a "volatile" keyword on roles that accept the player playing multiple roles.

Andreas Söderlund

unread,
Dec 18, 2015, 5:34:23 PM12/18/15
to object-co...@googlegroups.com, jcoplien/trygve
This is really interesting! I see the logic, and stage props is such a clever way of helping the programmer.

It reminds me somewhat of a C# compiler discussion, where someone wanted classes to be sealed by default. That makes me think that unless you really understand DCI, are you going to create roles instead of stage props, and later, perhaps even after you published a library, you realize the mistake? Some kind of "stage prop/const by default" could help the programmer here, a hint to think before modifying state. Does it make sense?

I'm really with you on keeping it simple, thinking about the probability that people will tell the compiler "I know what I'm doing", but don't understand the simple way of doing things (abusing the tool).

I'd really like trygve to help people programming, not just giving them full freedom and see them jump right back in the old paradigm, because of laziness, unaware about it, or something else. Quoting Alexander from The Phenomenon of Life, p. 293:

"Among natural phenomena, the fifteen properties seem to appear, pervasively, in almost everything. Yet among human artifacts, the fifteen properties appear only in the good ones. How can the very same properties be marks of good structure in human artifacts, and yet be present in all of nature? What is it about nature which always makes its structures "good"?

The essence of the problem is that we have not, as far as I know, ever yet concentrated our attention on the fact that in nature, all the configurations that do occur belong to a relatively small subset of all the configurations that could possibly occur. It is that which permits, I believe, the characterization of a certain class of structures as living structure."

Can we use this concept in trygve? It'll take some thinking for sure. As you said, where is the "decider" that an object can play multiple Roles concurrently? I'm thinking about the good old Money Transfer. It will obviously mutate state, does it mean that the Account objects can't be used anywhere else in their parent Context, or in some places? What places? What about long-running Contexts?

Thanks for your kind words about my code. It took a few years to get there, starting from the first time I read the article on Artima. :) Putting some examples up on fulloo.info would be nice. Oh, about sending code via email, I'm using github to open issues and send code there. If you open the issue there instead, you can copy and paste the code as it should be. But I can put them up on a git branch too, as I've done with the chord identifier. I'm enjoying this, it'll be a couple of fun months ahead!

/Andreas

--
You received this message because you are subscribed to the Google Groups "object-composition" group.
To unsubscribe from this group and stop receiving emails from it, send an email to object-composit...@googlegroups.com.
To post to this group, send email to object-co...@googlegroups.com.
Visit this group at https://groups.google.com/group/object-composition.
For more options, visit https://groups.google.com/d/optout.

Matthew Browne

unread,
Dec 18, 2015, 9:37:22 PM12/18/15
to object-co...@googlegroups.com
Hi Andreas,
I like your idea of a stage prop as a default for roles with no methods, but I'm wondering how that would work.
Just brainstorming here - and this may be too much of a radical departure - but the 'role' keyword could be used for both roles and stage props, and a mutable/immutable modifier could be used to distinguish the two. For example:

immutable role LowNote {}

And if roles with no methods were stage props by default, then you could leave off the "immutable" modifier and that would be the default:

role LowNote {}  //implicitly immutable

But on second thought, this convention could be confusing because I think it makes sense for roles with methods to be mutable by default.

So I'm not sure what would be a good approach, but I thought I'd share my brainstorming here.

BTW, I was just looking back at what I wrote here (somewhat prompted by your post) and noticed a typo:

On 12/15/15 8:47 AM, Matthew Browne wrote:
When would you use a role with no methods, as opposed to a stage prop? A stage prop ensures that the object isn't mutated from within that context, right? I'm guessing that in most cases, the player for a role with most methods wouldn't need to be mutated, so maybe I've answered my own question...
I meant to say:
"the player for a role with no methods wouldn't need to be mutated".

Rune Funch Søltoft

unread,
Dec 19, 2015, 3:47:50 AM12/19/15
to object-co...@googlegroups.com

> Den 18. dec. 2015 kl. 23.34 skrev Andreas Söderlund <cisc...@gmail.com>:
>
> I'm thinking about the good old Money Transfer. It will obviously mutate state
Depends on your definition of state. Talking about roles and stage props I dont see it's obvious.

It is a explicit design decision of Trygve, that force or at least supports a specific World view. In that view it's obvious but I don't think that World view is obvious. It's abstractions too much of the information away. However Cope already kones all that and have some compeling arguments for the decision so this is not to Challenge the design decision but the Statement that something is obvious because it fits a specific world view.

Matthew Browne

unread,
Dec 19, 2015, 9:12:06 AM12/19/15
to object-co...@googlegroups.com
Do you have a version of the money transfer example that doesn't mutate
state? * I'm sure it's possible as you say, but it would be nice to see
it for the sake of understanding. I'm not suggesting that we should try
to make trygve examples avoid state mutations (unless that makes them
more readable); I would just like to see a comparison of the two approaches.

Thanks,
Matt

* I know that in your Marvin example, the ledger entries are immutable,
but from the perspective of the MoneyTransfer context, the Account
object is mutable.

James O Coplien

unread,
Dec 19, 2015, 2:27:13 PM12/19/15
to object-co...@googlegroups.com

Den 19/12/2015 kl. 15.12 skrev Matthew Browne <mbro...@gmail.com>:

Do you have a version of the money transfer example that doesn't mutate state?

I’m not sure, but I think the most advanced example in the book doesn’t mutate state: it only appends to a transaction log. If it does mutate state it can be made not to.

There are many constructs in trygve to avoid gratuitously mutating state. They’re not fully implemented yet so I’ve not advertised them, but they’ll be coming. I view trygve in part as a stepping stone to an applicative language.

Andreas Söderlund

unread,
Dec 19, 2015, 5:14:59 PM12/19/15
to object-co...@googlegroups.com
Does that mean the Ledgers collection isn't mutated when something is added to it? 

The point I'm trying to make is that eventually something has to change, and if that something is playing a Role in another Context at the same time, there will be a concurrency problem. It could be difficult to figure out when that will happen, or am I misunderstanding something?



--

Rune Funch Søltoft

unread,
Dec 20, 2015, 3:39:25 AM12/20/15
to object-co...@googlegroups.com

> Den 19. dec. 2015 kl. 23.14 skrev Andreas Söderlund <cisc...@gmail.com>:
>
> Does that mean the Ledgers collection isn't mutated when something is added to it?
It shouldn't be.

Let's say you have to list of integers

2::[1] and
3::2::[1]

would you propose that they are the same set? I created the first set by adding a new "ledger entry" called '3'

The previous set represents the past the latter one represents the present. The present is based on the past but the present state is not a mutation of the past it's an addition to the past. So mutating it is a model that violates the concept of time

James O Coplien

unread,
Dec 20, 2015, 6:26:23 AM12/20/15
to object-co...@googlegroups.com

Den 19/12/2015 kl. 23.14 skrev Andreas Söderlund <cisc...@gmail.com>:

Does that mean the Ledgers collection isn't mutated when something is added to it? 

This gets into issues that border on philosophical arguments, and since we’re not in the philosophy business, pragmatics usually take over.

The actual mutated data is sitting on a disk somewhere in a database. A database record is not an object. There may be an object in memory that represents that database entry. Then again, maybe not. It is up to the user mental model whether we view the Ledgers as mutable or not.

One way to view this would be to let the program logic be pure functional. There are many advantages to side-effect-free programming, and that’s where I’m headed with trygve in the long term. Then have a separate partition that manages data persistence with a well-defined abstraction boundary between them. OTOH you can let your mental model require that the data have a representation “in memory.” But in banking there is no notion of “memory” in the mental model. And for the programmer’s mental model, unnecessarily bringing persistence into the model really messes it up: side-effects considered harmful.

(This is particularly interesting for the Ledgers case because Ledger entries are write-once and Ledgers are append-only. They are hardly suitable to an object model. And there’s a reason for that — it relates to reliability, easier transaction semantics and a bunch of other pragmatic advantages.)

James O Coplien

unread,
Dec 20, 2015, 6:27:12 AM12/20/15
to object-co...@googlegroups.com
I think we crossed in the mails, and said the same thing in two very different ways.

Trygve Reenskaug

unread,
Dec 20, 2015, 9:18:11 AM12/20/15
to object-co...@googlegroups.com
I have a simple mind and fail to grok what you are saying. I have 2 questions.

Consider a bank's Ledger that contains a set of transactions. Transactions can be added but neither changed nor removed.
  1. The balance of an account is computed by selecting and summing over the Ledger transactions.
  2. A transaction is added to the Ledger
  3. The balance of the same account is computed by selecting and summing over the Ledger transactions and yield a different result.
Question 1: Do you regard this Ledger as immutable? (I say it's changing and, therefore, mutable).

More than a billion people own and use computers today. My vision is that a proportion of them will also be programming their computers. This is my target audience. Its members will range from computing novices (most)  to experts. Your target audience may be different.

Question 2: Do you mean that the distinction between mutation and addition will help  your audience better understand programming?

Matthew Browne

unread,
Dec 20, 2015, 9:36:33 AM12/20/15
to object-co...@googlegroups.com
I think Rune was saying that in an immutable model, when a new transaction is added to a Ledgers collection, it would replace Ledgers object with a new collection object rather than mutating the existing one.

Suppose that's the case...now when adding a new transaction, you'd be re-binding the Ledgers role in the Account context to a new ledgers collection object. Is this a special case where role re-binding should be allowed?

Also, the state of the Account context itself is still being mutated, and Accounts are role-players in the MoneyTransfer context, so we still have not avoided mutation of role-players.

I have the same question as Trygve...how would it help to have all role players be immutable? And what would that even look like in this case? The only way I can envision it working is if the ledgers collections existed entirely outside the Account context, which I don't think makes sense...

Come to think of it, that leads me to another question: even with mechanisms like stageprops to prevent accidental state mutations within a particular Context, isn't there always the loophole of the Context asking some external code to make that state mutation instead? So in this example, the Account object could send a message to some other object that manages the ledgers (suppose that other object isn't even a Context), so Ledgers is no longer a role-player, but in the end, the in-memory representation of the ledgers is effectively the same.

rune funch

unread,
Dec 20, 2015, 9:53:03 AM12/20/15
to object-co...@googlegroups.com
2015-12-20 15:18 GMT+01:00 Trygve Reenskaug <try...@ifi.uio.no>:
I have a simple mind and fail to grok what you are saying. I have 2 questions.

Consider a bank's Ledger that contains a set of transactions. Transactions can be added but neither changed nor removed.
  1. The balance of an account is computed by selecting and summing over the Ledger transactions.
  2. A transaction is added to the Ledger
  3. The balance of the same account is computed by selecting and summing over the Ledger transactions and yield a different result.
Question 1: Do you regard this Ledger as immutable? (I say it's changing and, therefore, mutable).

No I would regard each ledger as a snapshot in time. Each of which would be immutable
 
More than a billion people own and use computers today. My vision is that a proportion of them will also be programming their computers. This is my target audience. Its members will range from computing novices (most)  to experts. Your target audience may be different.

Question 2: Do you mean that the distinction between mutation and addition will help  your audience better understand programming?

I think it would help them greatly to reason about the program. So if we can agree that that would help in better understanding programming then my answer to you 2nd question is yes 

Matthew Browne

unread,
Dec 20, 2015, 9:54:39 AM12/20/15
to object-co...@googlegroups.com
On 12/20/15 6:26 AM, James O Coplien wrote:
One way to view this would be to let the program logic be pure functional. There are many advantages to side-effect-free programming, and that’s where I’m headed with trygve in the long term.
I like trygve (and Trygve ;) ), but I have to ask: is trygve the best platform for that long-term vision?

I would love to see the trygve project eventually inspire a real language intended for production use. I think our long-term vision, however it evolves, would be best served by eventually ditching Java and class-based syntax entirely, and starting from scratch with a new syntax. I think the trygve language is best suited to the goal you mentioned at the outset: helping to inspire research interest in DCI and DCI semantics. While a more functional model could be an important part of future DCI semantics, do we really want to stretch Java all the way into that territory? Maybe we do, but as a practically-focused person I would rather see such an effort going into a real language. Maybe by that time we'll have generated enough research interest already that researchers wouldn't balk as something as trivial as installing something other than Java or other tool already on their machine.

James O Coplien

unread,
Dec 20, 2015, 10:07:48 AM12/20/15
to object-co...@googlegroups.com

Den 20/12/2015 kl. 15.54 skrev Matthew Browne <mbro...@gmail.com>:

I like trygve (and Trygve ;) ), but I have to ask: is trygve the best platform for that long-term vision?

I would love to see the trygve project eventually inspire a real language intended for production use. I think our long-term vision, however it evolves, would be best served by eventually ditching Java and class-based syntax entirely, and starting from scratch with a new syntax.

To me, trygve is more of a philosophy and a way of exploring the run-time environment than anything else. Your comments remind me of people who call Smalltalk a language. I think it kind of misses then point.

The Java-- syntax was chosen to get the environment into into people’s hands.

There has been some discussion around the ACCU community about classes-considered-evil and about removing the concept from languages (except for JavaScript, which is moving in the opposite direction). I think that’s throwing the baby out with the bath water. The class perspective is valuable, particularly from a domain-based architecture perspective. I can’t imagine why one would do away with the concept. And syntax is largely irrelevant — or even if it is relevant, we will never get consensus about which syntax is superior to which. So I don’t consider syntax to be at the core of my focus, and I certainly hope we don’t start arguing about that.

Oh, dear, it appears that we have. Well, let’s stop it right now.

Nonetheless, I can predict that in any such pissing contest, Java will win. 10 million Java programmers can’t be wrong. Well, of course, they can, but one would be a fool to pick a fight with 10 million of them. You will lose.

Matthew Browne

unread,
Dec 20, 2015, 10:42:05 AM12/20/15
to object-co...@googlegroups.com
On 12/20/15 10:07 AM, James O Coplien wrote:

Den 20/12/2015 kl. 15.54 skrev Matthew Browne <mbro...@gmail.com>:

I like trygve (and Trygve ;) ), but I have to ask: is trygve the best platform for that long-term vision?

I would love to see the trygve project eventually inspire a real language intended for production use. I think our long-term vision, however it evolves, would be best served by eventually ditching Java and class-based syntax entirely, and starting from scratch with a new syntax.

To me, trygve is more of a philosophy and a way of exploring the run-time environment than anything else. Your comments remind me of people who call Smalltalk a language. I think it kind of misses then point.
Do you envision the trygve environment ultimately being used as a VM for multiple different languages, one or more of which could be suitable for production use?

As to classes, I'm not completely against them, and I think they make sense in a language with a Java-like syntax. But they come with a lot of baggage. I think prototypes, forwarding, etc. are equally useful concepts that should be considered for support either alongside or as a replacement for classes. Most importantly, when creating a new language for object-oriented programming, I don't think the presence of classes should be a foregone assumption (I think I just made up that phrase :). And since you mentioned Javascript, I'll just point out that I don't think Javascript needs classes - a combination of prototypes and DCI contexts could be used instead.

Matthew Browne

unread,
Dec 20, 2015, 10:46:01 AM12/20/15
to object-co...@googlegroups.com
On 12/20/15 10:42 AM, Matthew Browne wrote:
And since you mentioned Javascript, I'll just point out that I don't think Javascript needs classes - a combination of prototypes and DCI contexts could be used instead.
* Yes, I'm aware that Javascript classes are just syntactic sugar for prototypes. I wish they had chosen a different word for the new construct.

James O Coplien

unread,
Dec 20, 2015, 10:56:45 AM12/20/15
to object-co...@googlegroups.com
Den 20/12/2015 kl. 15.54 skrev Matthew Browne <mbro...@gmail.com>:

While a more functional model could be an important part of future DCI semantics, do we really want to stretch Java all the way into that territory?

As it turns out, it’s already there. Most the of the semantics haven’t been debugged yet, but it’s all in the design and initial coding is all done.

There is a rich history of steps of such evolution going back 40 or 50 years. Consider the early FORTRAN program:

F(1)
        I = 1
PRINT 10, I
   10 FORMAT(I3)
STOP

PROCEDURE F(I)
INTEGER I
I = I + 1
RETURN
END

This would print the integer 2, because the integer “1” was volatile. So they made a change to FORTRAN that protected INTEGER literals from being modified (basically with some compiler aids). It was not a monumental change to the computing paradigm, but it made the world safer.

In general the enemy here is side-effects. To avoid side-effects is a time-honored and well-known programming approach. It is why we avoid shared or global data. Those who still think in terms of Von Neumann machines have difficult breaking their dependency on side-effects. It’s a new way of thinking about what a computer is.

Here’s another small step. Consider the trygve script:

int fact(int n) {
int retval;
if (n <= 1) {
retval = 1
} else {
int t = fact(n - 1);
retval = n * t
}
return retval
}

We all remember the difficulty in reasoning about the multiplicity in appearances of the object t. Instead, we should just be able to articulate our mental model, which we picked up in mathematics:

int fact(int n) {
return if (n <= 1) 1 else n * fact(n - 1)
}

I thought Trygve would be surprised when he saw this. He wasn’t. He found it perfectly natural. It is a small first step to taking “Java features” into higher order computation. It all comes down to a Turing machine in the end and there are only two or three basic things you can do, so it’s just a matter of expressing how to do them. Java isn’t all bad at doing that. Even a layperson would probably find it better than first-order predicate Calculus.

I won’t even mention that it’s shorter and easier to comprehend than the side-effect-laden version — for both humans and compilers.

The only use of n here is to provide a boundary between components of mental chunking. In trygve it doesn’t create a new object — only an alias for a name in another chunk, that we decided to separate into its own locus of being able to be reasoned about. In C it does create a new object. In Java — well, it depends, because Java is schizophrenic in its type system, like C++. That schizophrenia doesn’t exist in trygve. It doesn’t exist in the “good parts” of Java where you avoid groveling in the bits and thinking of assignment as shoveling bits around.

Advanced forms of this are called currying, and one can thereby introduce immense computational efficiency into a computation. You can enable the program to evaluate only what is absolutely necessary for the pulled result. You can do so without all the fancy data slicing algorithms that most compilers use to get efficiency.

This trygve approach is to apply this concept reasonably across language features. Consider Andreas’ code:

public int position() const {
        int pos = 0;
        if(name_ == "C")  pos = 1;
        if(name_ == "C#") pos = 2;
        if(name_ == "Db") pos = 2;
      if(name_ == "D")  pos = 3;
      if(name_ == "D#") pos = 4;
      if(name_ == "Eb") pos = 4;
      if(name_ == "E")  pos = 5;
    if(name_ == "F")  pos = 6;
    if(name_ == "F#") pos = 7;
    if(name_ == "Gb") pos = 7;
    if(name_ == "G")  pos = 8;
    if(name_ == "G#") pos = 9;
    if(name_ == "Ab") pos = 9;
  if(name_ == "A")  pos = 10;
  if(name_ == "A#") pos = 11;
  if(name_ == "Bb") pos = 11;
  if(name_ == "B")  pos = 12;
  return pos;
}

The eventual trygve version will look like this:

public int position() const {
         return
switch (name_) {
         case "C")  1; break
         case "C#")
         case "Db") 2; break
        case "D")  3; break
        case "D#")
        case "Eb") 4; break
       case "E")  5; break
     case "F")  6; break
      case "F#")
     case "Gb") 7; break
      case "G")  8; break
     case "G#")
     case "Ab") 9; break
   case "A")  10; break
   case "A#")
   case "Bb") 11; break
   case "B")  12; break
}
}

This would work right now except for some typing bugs that I’m working.

Side-effect-free programming.

Now: consider that this logic was part of a functor, which meant that pos was part of the state. That would prevent the object from playing a Stage Prop, because its methods wouldn’t be const. With these constructs we can eliminate some of the intermediate state from programs, give them a more functional feel, and make more objects amenable to using Stage Props. That means more Stage Props and fewer Roles. That means that an object can more easily play in multiple Contexts at once without having to worry about all that garbage related to one Role modifying state on which another Role depends — a big win.

Insisting on retaining the notion of state will severely cripple an object’s ability to play multiple Roles — or we could just type everything volatile and hope for the best.

Nah, we can do better than that.

James O Coplien

unread,
Dec 20, 2015, 10:58:53 AM12/20/15
to object-co...@googlegroups.com

Den 20/12/2015 kl. 16.42 skrev Matthew Browne <mbro...@gmail.com>:

Do you envision the trygve environment ultimately being used as a VM for multiple different languages, one or more of which could be suitable for production use?

No. The product is learning. It’s a prototype. Conscionable programmers never deliver prototypes, They throw them away.

That said, I can see mapping the concepts onto existing environments, like the JVM. The JVM is much more powerful than Java can express — don’t be fooled. I’d love to put multiple dispatch into trygve. But people are still struggling with the basics...

Matthew Browne

unread,
Dec 20, 2015, 11:32:42 AM12/20/15
to object-co...@googlegroups.com
I was playing around some more with trygve, and I notice that stageprops
can contain methods as long as those methods don't mutate the object
bound to that stageprop. So I am wondering about the term "stage
prop"...a prop is an inanimate object. If role methods are like scripts
that an actor performs on stage, then the notion of scripts for stage
props seems odd to me. Of course all metaphors break down somewhere...

Another small thing I noticed: it seems that trygve does not allow
variable names beginning with an underscore - is that intentional? If we
are trying to make this language accessible to Java programmers, then I
think allowing at least private property names to begin with underscores
is important, and should perhaps even be the default convention. (Yes, I
realize that C++ programmers are used to seeing the underscore at the
end, so that's an OK convention too, but I think both should be allowed.)

James O Coplien

unread,
Dec 20, 2015, 12:20:37 PM12/20/15
to object-co...@googlegroups.com

> Den 20/12/2015 kl. 17.32 skrev Matthew Browne <mbro...@gmail.com>:
>
> If role methods are like scripts that an actor performs on stage, then the notion of scripts for stage props seems odd to me

You’ll get used to it.

James O Coplien

unread,
Dec 20, 2015, 2:00:45 PM12/20/15
to object-co...@googlegroups.com
Den 20/12/2015 kl. 17.32 skrev Matthew Browne <mbro...@gmail.com>:

Another small thing I noticed: it seems that trygve does not allow variable names beginning with an underscore - is that intentional? If we are trying to make this language accessible to Java programmers, then I think allowing at least private property names to begin with underscores is important, and should perhaps even be the default convention. (Yes, I realize that C++ programmers are used to seeing the underscore at the end, so that's an OK convention too, but I think both should be allowed.)

There is a longstanding tradition in programming, most notably those that spring from the BCPL-, B- and C- based cultures and from UN*X programming, that leading underscores are reserved for internal and system use. It long predates C++ and is much broader than just C. The same sentiment holds broadly for most Microsoft software and the use of leading underscores is explicitly discouraged in the CLS. It’s outright illegal in Delphi (yes, there are still a lot of Delphi programmers, particularly in the Balkans).

I don’t want trygve code to look like computer code — at least to the extent that is possible within Java confines.

There are tougher restrictions that are somewhat more conventional. Many internal trygve variables use embedded “$” characters. In one case, I use a leading space (the name of the class from which Class is instantiated starts with a space, as I recall). The lexer doesn’t accept any of these so it’s impossible to alias internal program names.

There are other restrictions on naming, but that’s an Easter egg and I’m going to leave it to others to discover… No fair looking at the code!

Speaking of B and C… What *should* C++ have been named if it had followed history?

Matthew Browne

unread,
Dec 20, 2015, 2:18:49 PM12/20/15
to object-co...@googlegroups.com

Ok, thanks for the good explanation. I think something to that effect should be included in the documentation, or at least a simple statement that leading underscores are not allowed in variable names (and I'm guessing method names too?).

Sent from my Android phone

--

Matthew Browne

unread,
Dec 20, 2015, 2:21:50 PM12/20/15
to object-co...@googlegroups.com
Haha, I suppose I will. But I still think a valid alternative would be to have a mutable/immutable modifier for role constructs. Then they're all roles, it's just a question of what kind of role. That seems simpler to me, but perhaps to others it's simpler to have two separate concepts.

--
Sent from my Android device with K-9 Mail.

James O Coplien

unread,
Dec 20, 2015, 2:23:39 PM12/20/15
to object-co...@googlegroups.com
Den 20/12/2015 kl. 16.42 skrev Matthew Browne <mbro...@gmail.com>:

I think prototypes, forwarding, etc. are equally useful concepts that should be considered for support either alongside or as a replacement for classes.

I strongly disagree. As I communicated to the ACCU community, most people who use prototype-based language end creating class-like entities, anyhow: we might as well give them a language that gives expression to that. And the proper semantics of a classless language are far beyond the ability of most people — even expert programmers — to comprehend. I’ll bet that 90% of the people on this list don’t even know that the Treaty of Orlando exists, let alone what it says (btw, it was just posted to Research Gate after these many years) or are conversant in the seminal work of Stein in this area. She and Smith and Ungar had to get into some really gnarly bits to sort this all out, and the result was the quite elegant aforementioned Treaty.

Understanding proper classless OO where you still want to create loci of encapsulated functions requires a good appreciation of thunk-like behavior, and it’s hard to hide that inside the compiler. And it’s much tougher than Algol-68 thunks because you have both a procedure and data context. (We risk the same thing in DCI, by the way, and I’ll be raising the issue here later. In fact there are two “self” pointers in trygve Role methods: one for the current Role-player (this) and the other for the current Context (current$context). This makes it feasible to, for example, allow unqualified calls to Context superclass methods from methods of its Roles. Is that a good idea? It’s not just an idle concern: the assert facility is defined in class Object, from which all Context and Class instances now inherit. Should one be able to invoke assert from within a Role method, such that the method lookup finds it through current$context? Before you are hasty to answer, remember that other Role names are resolved through current$context already… So a lot of design work remaining to be explored.


Most importantly, when creating a new language for object-oriented programming, I don't think the presence of classes should be a foregone assumption (I think I just made up that phrase :). 

I assumed nothing in crafting trygve. Most aspects of its design were carefully considered — otherwise, it would have been done long before this.

Matthew Browne

unread,
Dec 20, 2015, 4:07:35 PM12/20/15
to object-co...@googlegroups.com
Speaking of conventions, how about a convention of role names beginning with a lowercase letter? (Uppercase would still be fine as far as the parser is concerned, of course.)

I don't think it's a big deal, but if we want to encourage object-oriented thinking, IMO camelCase role names (rather than PascalCase) are preferable - PascalCase is reminiscent of classes, whereas role identifiers resolve to an instance.

There is one issue with camelCase role names though, as I discovered in earlier private discussions with Marc, which is the naming of role-player constructor arguments. So for example, if we have:

public TransferMoney(Account source, Account destination, float amount) {
  ...
}


Then there's a name conflict if we want roles called 'source', 'destination', and 'amount' (lowercase). In ScalaDCI, this is a non-issue because each constructor argument is automatically bound to a role if a role of the same name exists, so that the following sort of assignment code isn't necessary if you're following that convention:

Source = source;
Destination = destination;
Amount = amount;


I think this is an elegant solution, but it's less explicit so perhaps not as beginner-friendly...I haven't fully made up my mind about it. It's more of a wish-list feature anyway, but I thought I'd mention it as we begin creating more examples and establishing conventions as we go...

Matthew Browne

unread,
Dec 20, 2015, 4:15:30 PM12/20/15
to object-co...@googlegroups.com
On 12/20/15 2:23 PM, James O Coplien wrote:
Den 20/12/2015 kl. 16.42 skrev Matthew Browne <mbro...@gmail.com>:

I think prototypes, forwarding, etc. are equally useful concepts that should be considered for support either alongside or as a replacement for classes.

I strongly disagree. As I communicated to the ACCU community, most people who use prototype-based language end creating class-like entities, anyhow: we might as well give them a language that gives expression to that.
Good point. But should trygve or any new DCI language include all the features of traditional classes, or only some of them? i.e. should it include traditional inheritance, including protected properties, 'super' calls and all the rest from the classes we know and love/hate?

I see that in trygve, the 'extends' keyword is allowed for classes, but not contexts. This is in accordance with previous discussions, but what about contexts that are part of the domain model rather than public-facing use cases?

And the proper semantics of a classless language are far beyond the ability of most people — even expert programmers — to comprehend. I’ll bet that 90% of the people on this list don’t even know that the Treaty of Orlando exists, let alone what it says (btw, it was just posted to Research Gate after these many years) or are conversant in the seminal work of Stein in this area. She and Smith and Ungar had to get into some really gnarly bits to sort this all out, and the result was the quite elegant aforementioned Treaty.

Understanding proper classless OO where you still want to create loci of encapsulated functions requires a good appreciation of thunk-like behavior, and it’s hard to hide that inside the compiler. And it’s much tougher than Algol-68 thunks because you have both a procedure and data context. (We risk the same thing in DCI, by the way, and I’ll be raising the issue here later. In fact there are two “self” pointers in trygve Role methods: one for the current Role-player (this) and the other for the current Context (current$context). This makes it feasible to, for example, allow unqualified calls to Context superclass methods from methods of its Roles. Is that a good idea? It’s not just an idle concern: the assert facility is defined in class Object, from which all Context and Class instances now inherit. Should one be able to invoke assert from within a Role method, such that the method lookup finds it through current$context? Before you are hasty to answer, remember that other Role names are resolved through current$context already… So a lot of design work remaining to be explored.


Most importantly, when creating a new language for object-oriented programming, I don't think the presence of classes should be a foregone assumption (I think I just made up that phrase :). 

I assumed nothing in crafting trygve. Most aspects of its design were carefully considered — otherwise, it would have been done long before this.

James O Coplien

unread,
Dec 20, 2015, 5:53:47 PM12/20/15
to object-co...@googlegroups.com

Den 20/12/2015 kl. 22.07 skrev Matthew Browne <mbro...@gmail.com>:

Speaking of conventions, how about a convention of role names beginning with a lowercase letter? 

I almost always use uppercase!!! I think Trygve does, too, but I’d have to go back and look.

I’m big on pushing consistent style. What do the rest of you use?

James O Coplien

unread,
Dec 20, 2015, 6:04:25 PM12/20/15
to object-co...@googlegroups.com
Den 20/12/2015 kl. 22.15 skrev Matthew Browne <mbro...@gmail.com>:

Good point. But should trygve or any new DCI language include all the features of traditional classes, or only some of them? i.e. should it include traditional inheritance, including protected properties, 'super' calls and all the rest from the classes we know and love/hate?

I’m being VERY careful with this. I thought long and hard before allowing inheritance at all. You can now use it, but it uses a more Smalltalk-style lookup than the horribly broken Java-style lookup with overloading across scopes… I borrowed many of the tyrranical scope locality conventions of C++ and strengthened them: there is no special relationship between base and derived classes with respect to access permission. I consider protected to be a violation of encapsulation of the base class and disallow it.

I am very firm about leaving the concept of super out of the language — I consider it to be broken. It’s fragile with respect to inserting new classes in the hierarchy (and other popular refactoring techniques). C++ does it right if you want to do class-oriented programming — which I do not. I have quietly put in some derived / base constructor orchestration stuff, but did so only out of necessity (hint: it’s more in the spirit of the C++ approach, and I limit the amount of it that’s automagical). I may not advertise it. But it’s there to experiment with and, if the need arises, I’ll point it out to people.

There are oodles of other detailed inheritance considerations that I dealt with one at a time, always with simple, outward-facing mental models in mind and a bit of scorn for computer linguists.

No multiple inheritance, of course.

So, as you see, this is NOT Java. I borrowed some of the syntax to make it look more than superficially similar. But all the semantics are clearly thought out from scratch.

Rune Funch Søltoft

unread,
Dec 21, 2015, 12:54:26 AM12/21/15
to object-co...@googlegroups.com


> Den 20. dec. 2015 kl. 22.07 skrev Matthew Browne <mbro...@gmail.com>:
>
> PascalCase is reminiscent of classes, whereas role identifiers resolve to an instance.
That entirely depends on your background

Egon Elbre

unread,
Dec 21, 2015, 1:01:20 AM12/21/15
to object-composition
Depends on the language, but I've grown to like the Go approach: 
uppercase -> public/large-scope/important; lowercase -> private/small-scope/unimportant.

By this rationale I would use uppercase -- roles should stand-out, in the context, from the rest of the line-noise.

+ Egon

Rune Funch Søltoft

unread,
Dec 21, 2015, 1:09:59 AM12/21/15
to object-co...@googlegroups.com
I use a similar convention when writing C#. Camel when local public when it's not and backing fields start with an underscore. 

In F# I'm converting to something similar but since the primroses expressed are different from C# the convention at times feel wrong




+ Egon

Andreas Söderlund

unread,
Dec 21, 2015, 1:10:03 AM12/21/15
to object-co...@googlegroups.com
mån 21 dec. 2015 kl 07:01 skrev Egon Elbre <egon...@gmail.com>:
uppercase -> public/large-scope/important; lowercase -> private/small-scope/unimportant.

By this rationale I would use uppercase -- roles should stand-out, in the context, from the rest of the line-noise.

I agree with having Roles and Stageprops as uppercase. They are important and should have the attention they deserve! But then what about "this" in a RoleMethod?

Egon Elbre

unread,
Dec 21, 2015, 1:41:57 AM12/21/15
to object-composition, cisc...@gmail.com
Replace it with the role name :)

Andreas Söderlund

unread,
Dec 21, 2015, 3:05:22 AM12/21/15
to object-co...@googlegroups.com
mån 21 dec. 2015 kl 07:41 skrev Egon Elbre <egon...@gmail.com>:

I agree with having Roles and Stageprops as uppercase. They are important and should have the attention they deserve! But then what about "this" in a RoleMethod?

Replace it with the role name :)

Sure, but I vaguely remember some discussion way back about self/this, and the strange notion of calling yourself by your own name in third person. So I'm a bit hesitant... :)

Trygve Reenskaug

unread,
Dec 21, 2015, 4:33:06 AM12/21/15
to object-co...@googlegroups.com
I have suggested that we distinguish role names with ALLCAPS.

Egon Elbre

unread,
Dec 21, 2015, 4:36:33 AM12/21/15
to object-composition, cisc...@gmail.com
It's a matter of perspective.

When you use the role name, it uses third-person narrative instead of first-person. You are describing what Source and Account do, rather than what Source sees what it is doing.

In one you are the protagonist(s) in the other an observer.

+ Egon

Trygve Reenskaug

unread,
Dec 21, 2015, 4:36:47 AM12/21/15
to object-co...@googlegroups.com
+1

Trygve Reenskaug

unread,
Dec 21, 2015, 4:47:27 AM12/21/15
to object-co...@googlegroups.com


On 20.12.2015 15:52, rune funch wrote:
2015-12-20 15:18 GMT+01:00 Trygve Reenskaug <try...@ifi.uio.no>:
I have a simple mind and fail to grok what you are saying. I have 2 questions.

Consider a bank's Ledger that contains a set of transactions. Transactions can be added but neither changed nor removed.
  1. The balance of an account is computed by selecting and summing over the Ledger transactions.
  2. A transaction is added to the Ledger
  3. The balance of the same account is computed by selecting and summing over the Ledger transactions and yield a different result.
Question 1: Do you regard this Ledger as immutable? (I say it's changing and, therefore, mutable).

No I would regard each ledger as a snapshot in time. Each of which would be immutable
 
It seems we have to agree to disagree then.
To me, a Ledger is represented by an object that encapsulates a set of Transactions. A new Transaction is simply added to the set. The Ledger is mutable.
If I read you right, the addition of a new Transaction implies creating a new Ledger that includes the new Transaction and then moving all the Transactions from the old to the new Ledger. Some of the references to the old Ledger will have to be updated, making these references mutable.  Sounds complicated to me, and I may change my mind when I get a better understanding of your model.

Trygve Reenskaug

unread,
Dec 21, 2015, 4:55:58 AM12/21/15
to object-co...@googlegroups.com


On 20.12.2015 16:07, James O Coplien wrote:

Den 20/12/2015 kl. 15.54 skrev Matthew Browne <mbro...@gmail.com>:

I like trygve (and Trygve ;) ), but I have to ask: is trygve the best platform for that long-term vision?

I would love to see the trygve project eventually inspire a real language intended for production use. I think our long-term vision, however it evolves, would be best served by eventually ditching Java and class-based syntax entirely, and starting from scratch with a new syntax.

To me, trygve is more of a philosophy and a way of exploring the run-time environment than anything else. Your comments remind me of people who call Smalltalk a language. I think it kind of misses then point.
Yes, yes, yes. I look for a mental model of what goes on in the computer while it is executing a program. The DCI execution model as expressed in the Trygve language may still be less than satisfactory. Cope has given us a lab where we can experiment with alternative execution models and different stories to explain the models. Application programs seen as text files written in a certain language may become as outdated as the "remember-and-type" interfaces you see in Windows command prompts or Unix shells. Traditional languages may continue to exist as intermediate languages such as MSIL; they are not meant for human consumption. 

The mental model is the essence, there will probably be several intermediate languages and even more different IDEs. In MVC terms, our focus is on the Model of a program. We can only make the discussion concrete by discussing Views with their IDEs, languages, and examples. I see Trygve as a View on the DCI model of a program.

James O Coplien

unread,
Dec 21, 2015, 4:59:57 AM12/21/15
to object-co...@googlegroups.com

Den 21/12/2015 kl. 10.55 skrev Trygve Reenskaug <try...@ifi.uio.no>:

our focus is on the Model of a program

Holy cow. Somehow I think that just might be a powerful phrase with layers of meaning that go very deep.

Linguistically it takes us from semantics into epistemology and hermeneutics...

Egon Elbre

unread,
Dec 21, 2015, 5:00:47 AM12/21/15
to object-composition
I'm in-between those two views.

When you have a Ledger (the book kind), when you write a new entry... you wouldn't say, yup, this is a new Ledger, it's still the same Ledger... however the content/state is different.

The Ledger was modified, not just added to it. Even by doing nothing, the Ledger is collecting dust. The identity is the same throughout time, however the state is not.

When you have two books, same print, same content... would you call it one book?

+ Egon

James O Coplien

unread,
Dec 21, 2015, 5:12:34 AM12/21/15
to object-co...@googlegroups.com
There is a third element here which I think either enlightens the discussion and supports Rune’s point or which just may, on the other hands, confuse things…

A bank’s transaction log isn’t an ordinary set of data. In banking traceability is sacred and history must be immutable. So I can’t change the (old) state of a transaction: I can only add to it. Neither Trygve’s current position nor Rune’s current position accommodate this…

If you view a transaction log as a collection that grows by recursively adding a new element on top of the existing one, then it’s closer to Rune’s model. One could create an object (in memory) that provides an abstraction layer (do I get points for terminology?) to these two things as an ensemble: the old immutable log and the new entry. That in-core object represents only an object in the end-user mental model. But once instantiated, it is never changed. If I add a new record to the log I create a new such object that takes the existing one as its immutable history and adds a new one. Again, once created, it is never changed.

I think that part of the confusion here lies in the space between the banking auditor’s mental model of transaction lots and the account-holder’s mental model of accounts. I think what I describe above accurately reflects the auditors’ model. I think maybe Trygve is thinking of the end user model of accounts which, of course, are mutable. They change their association to transaction logs with every transaction.

However, transaction logs are normally not part of the account-holder mental model.

And in this case, the programmer mental model of a transaction is going to be closer to that of the auditor than that of the account holder — because it rather has to be so…

Warning: This is just one mental model. There may be others. But I think this mental model is faithful to banking norms, culture, and history, while the “mutable log” model is more a CS perspective. I have been trying to train myself to suppress the latter. Sometimes it leads to some powerful insights from other parts of CS, which is the case here. And, of course, one can reduce the immutable, recursive data model to an iterative, stateful data model – just the opposite of what I did with the factorial example I posted here a couple of days ago.



James O Coplien

unread,
Dec 21, 2015, 5:14:38 AM12/21/15
to object-co...@googlegroups.com

Den 21/12/2015 kl. 11.00 skrev Egon Elbre <egon...@gmail.com>:

When you have two books, same print, same content... would you call it one book?

It depends on the domain and mental model. As an author: yes. As a publisher: no. As a reader: no. The use case for an audio book is quite different from that for a printed book. There is an aspect of both books that is the same. But just because they both have the same content doesn’t make them the same book, any more than being red makes an apple a fire engine.

James O Coplien

unread,
Dec 21, 2015, 5:17:25 AM12/21/15
to object-co...@googlegroups.com

Den 21/12/2015 kl. 11.12 skrev James O Coplien <jcop...@gmail.com>:

Warning: This is just one mental model. There may be others. But I think this mental model is faithful to banking norms, culture, and history, while the “mutable log” model is more a CS perspective. I have been trying to train myself to suppress the latter. Sometimes it leads to some powerful insights from other parts of CS, which is the case here. And, of course, one can reduce the immutable, recursive data model to an iterative, stateful data model – just the opposite of what I did with the factorial example I posted here a couple of days ago.

I would just add that this leads to yet another perspective: that of the programmer. if the programmer chooses to make the transaction log a mutable object, then it is a departure from all end-user mental models. In DCI I think we should favour the end user models and do the reverse-factorial optimization only with circumspection, thorough explanation, intense analysis, and care.

Trygve Reenskaug

unread,
Dec 21, 2015, 5:21:09 AM12/21/15
to object-co...@googlegroups.com


On 20.12.2015 16:56, James O Coplien wrote:
Den 20/12/2015 kl. 15.54 skrev Matthew Browne <mbro...@gmail.com>:

While a more functional model could be an important part of future DCI semantics, do we really want to stretch Java all the way into that territory?

As it turns out, it’s already there. Most the of the semantics haven’t been debugged yet, but it’s all in the design and initial coding is all done.


I have been speculating if our Context should be seen as a functional layer on top of an object layer rather than being infused into the objects. May be Trygve can help us experiment with such models.  It could resolve the conflict between insertion-ful/insertion-less models because we wouldn't use any of them. I played with this idea in "DCI.runtime-0.1.pdf" of 2015.03.25 when I though of the roles and role methods as proxies in front of the Data objects.

rune funch

unread,
Dec 21, 2015, 5:38:23 AM12/21/15
to object-co...@googlegroups.com

2015-12-21 10:47 GMT+01:00 Trygve Reenskaug <try...@ifi.uio.no>:
the addition of a new Transaction implies creating a new Ledger that includes the new Transaction and then moving all the Transactions from the old to the new Ledger. Some of the references to the old Ledger will have to be updated, making these references mutable.

Oh no not by far, This might be true in a specific world view but I'm explicitly challenging that world view. In my oppinion that world view leads to a lot of misunderstandings that in general leads to overcomplicating simple stuff. For some reason that seems to be especially true in the Java world.

The addtition is very straight forward an no references are changed. It's an addition not an alteration. A simple class based implementation 

class Ledger {
    private Ledger past_;
    private LedgerEntry head_;
    private Ledger (LedgerEntry entry, Ledger past) {
        past_ = past;
        head_ = entry;
    }
public static Empty(){ return empty_;}
public Add(LedgerEntry entry){return new Ledger(entry, this);} 
}

Egon Elbre

unread,
Dec 21, 2015, 5:58:27 AM12/21/15
to object-composition
You still have to store the "current head" or "head at timepoint X" somewhere, otherwise you cannot reach it in the future.

Rune Funch Søltoft

unread,
Dec 21, 2015, 6:42:45 AM12/21/15
to object-co...@googlegroups.com


> Den 21. dec. 2015 kl. 11.58 skrev Egon Elbre <egon...@gmail.com>:
>
> You still have to store the "current head" or "head at timepoint X" somewhere, otherwise you cannot reach it in the future.

I have to store all of it somewhere to be able to reach it put that is rather unrelated to where I'd allow to mutate what is already stored

Matthew Browne

unread,
Dec 21, 2015, 11:05:18 AM12/21/15
to object-co...@googlegroups.com
I thought it was nice for roles to stand out too, but in an earlier conversation I had with Marc he pointed out that role names could be easily highlighted in an IDE.

The basic issue with PascalCase is that to a lot of programmers (not all, clearly) it looks like a static method call, which is the opposite of the object-oriented thinking we want to encourage.

So that's the argument for camelCase, but I don't have a strong feeling about it one way or the other, I just thought we should discuss it. Given the current lack of IDE support and features for automatic role-binding of constructor arguments, I'm fine with PascalCase as long as I have the option to change my mind in the future.

Matthew Browne

unread,
Dec 21, 2015, 6:24:11 PM12/21/15
to object-co...@googlegroups.com
On 12/21/15 4:33 AM, Trygve Reenskaug wrote:
I have suggested that we distinguish role names with ALLCAPS.
All caps is my least preferred option. I usually have only used all caps for constants. I know it's trivial, but I find it inconvenient to switch to caps lock and I don't see any significant advantage of using all caps for role names. I also doubt that this is a convention that all or most programmers would follow...it's just not a style people are used to these days.

Matthew Browne

unread,
Dec 21, 2015, 6:43:51 PM12/21/15
to object-co...@googlegroups.com
I still don't see how you would be able to use only stage props and not roles, e.g.:

context TransferMoney {
    ...
    stageprop Source {   
        ...
    }
    ...

    stageprop Destination {
        ...
    }
    ...

    stageprop Amount {}
}


Even if the ledger (i.e. collection of ledger entries) is immutable, when you change the reference to the updated ledger in the Account context, you're changing the state of the Account role-player in the TransferMoney context so I don't think you can use stage props for Source and Destination...? At least not if we keep the increaseBalance() / decreaseBalance() API.

Rune Funch Søltoft

unread,
Dec 22, 2015, 2:29:53 AM12/22/15
to object-co...@googlegroups.com


> Den 22. dec. 2015 kl. 00.43 skrev Matthew Browne <mbro...@gmail.com>:
>
> when you change the reference to the updated ledger in the Account context

In these Star Wars times let me answer with a quote "You assume too much" I don't believe in rebinding role players remember. So I wouldn't update any reference.

Trygve Reenskaug

unread,
Dec 22, 2015, 3:48:09 AM12/22/15
to object-co...@googlegroups.com
That somewhere is what I call the Ledger. It's already stored. It's not unrelated to the the Transactions, it has links to all of them (it's their container). And, as you, say it's mutable.

rune funch

unread,
Dec 22, 2015, 4:32:23 AM12/22/15
to object-co...@googlegroups.com
That somewhere is what I call the Ledger. It's already stored. It's not unrelated to the the Transactions, it has links to all of them (it's their container). And, as you, say it's mutable.

That what was I fear but wouldn't assume because that reduces the discussion of immutability to the point where immutability is unattainable because you can always claim that "oh no it's not immutable because you have to store it in memory" that's in my view a very boring discussion and it's still based on a fundamental assumption that we are dealing with a von neumann architecture. 

James O Coplien

unread,
Dec 22, 2015, 7:37:03 AM12/22/15
to object-co...@googlegroups.com

Den 21/12/2015 kl. 17.05 skrev Matthew Browne <mbro...@gmail.com>:

that role names could be easily highlighted in an IDE.

So you’re volunteering to put this into trygve? ;-)

Matthew Browne

unread,
Dec 22, 2015, 10:22:46 AM12/22/15
to object-co...@googlegroups.com
Haha yes, I remember that, and I should have mentioned that that's an
additional reason I don't understand how your suggestion would work.

Getting back to your original statement:

On Saturday, December 19, 2015 at 3:47:50 AM UTC-5, Rune wrote:
> > Den 18. dec. 2015 kl. 23.34 skrev Andreas Söderlund
> <cisc...@gmail.com>:
> >
> > I'm thinking about the good old Money Transfer. It will obviously
> mutate state
> Depends on your definition of state. Talking about roles and stage
> props I dont see it's obvious.
Perhaps this debate hinges on the definition of state. When I read this,
I thought you were talking about an implementation in which
SourceAccount and DestinationAccount are both stage props (and the
ledgers collection is also a stage prop); did I misunderstand? Because I
don't see how such an implementation is possible. Were you referring
only to the bank auditor's perspective, not the bank customer's perspective?

Rune Funch Søltoft

unread,
Dec 22, 2015, 10:34:41 AM12/22/15
to object-co...@googlegroups.com
If you were not constrained by the context having its role players rebound but instead it could yield a new context as the result. How would you solve it?

Matthew Browne

unread,
Dec 22, 2015, 11:14:51 AM12/22/15
to object-co...@googlegroups.com
On 12/22/15 10:34 AM, Rune Funch Søltoft wrote:
If you were not constrained by the context having its role players rebound but instead it could yield a new context as the result. How would you solve it?
I suppose one could do it like this:

public void transfer() {
    Account newSrc = Source.withdraw();
    Account newDst = Destination.deposit();
    return new TransferMoney(newSrc, newSrc, Amount);
}


...So now that you mention it, it is possible. But I don't see how that makes the code easier to reason about.

Trygve Reenskaug

unread,
Dec 22, 2015, 12:28:25 PM12/22/15
to object-co...@googlegroups.com

On 22.12.2015 00:24, Matthew Browne wrote:
On 12/21/15 4:33 AM, Trygve Reenskaug wrote:
I have suggested that we distinguish role names with ALLCAPS.
All caps is my least preferred option. I usually have only used all caps for constants.
I'm suggesting CONSTANTS and ROLENAMES.

I know it's trivial, but I find it inconvenient to switch to caps lock and I don't see any significant advantage of using all caps for role names.
It's not trivial, it's about the communication channel between brain and computer. I'm concerned about readability, not typing. A role name is a special kind of beast so it should have a special typography, IMO. It was a revelation to me when I got to PARC and they used general text with upper and lower case, bold, italics and even different fonts for code; it made programs much more readable.
I also doubt that this is a convention that all or most programmers would follow...it's just not a style people are used to these days.
I Don't expect to introduce a new way of programming without somebody changing their habits.  FORTRAN PEOPLE WROTE THEIR PROGRAMS IN ALL UPPERCASE, while algol people used all lower case and C-programmers use a richer mix of UPPER and lower case. Prettyprinters automatically fix more sophisticated conventions. I expect future programmers to use an IDE that includes a prettyprinter. In the meantime, it's far too cumbersome to type RoleNAME with small caps and I'll just capitalize the first letter and use the special typography in articles. BTW, Framemaker all caps leaves upper case letters unchanged and convert lower case to small caps. I haven't found another editor with this obvious algorithm.


James O Coplien

unread,
Dec 22, 2015, 1:00:47 PM12/22/15
to object-co...@googlegroups.com
أنا ذاهب لبدء البرمجة باللغة العربية.


Rune Funch Søltoft

unread,
Dec 22, 2015, 4:22:22 PM12/22/15
to object-co...@googlegroups.com

Den 22. dec. 2015 kl. 17.14 skrev Matthew Browne <mbro...@gmail.com>:

I suppose one could do it like this:

public void transfer() {
    Account newSrc = Source.withdraw();
    Account newDst = Destination.deposit();
    return new TransferMoney(newSrc, newSrc, Amount);
}


...So now that you mention it, it is possible. But I don't see how that makes the code easier to reason about.

I see little reason why you would want a context for transferring the same amount between the same accounts once again. Which was my second point. Why is the reference to the current important when the execution is done?  I agree that the code above could be improved from a readability perspective by not having references for objects that aren't needed and in general if you need the result of a calculation you should of course just make sure that the result is actually returned if you wish the operation to be side effect free

Matthew Browne

unread,
Dec 22, 2015, 7:40:59 PM12/22/15
to object-co...@googlegroups.com
On 12/22/15 4:22 PM, Rune Funch Søltoft wrote:

Den 22. dec. 2015 kl. 17.14 skrev Matthew Browne <mbro...@gmail.com>:

I suppose one could do it like this:

public void transfer() {
    Account newSrc = Source.withdraw();
    Account newDst = Destination.deposit();
    return new TransferMoney(newSrc, newSrc, Amount);
}


...So now that you mention it, it is possible. But I don't see how that makes the code easier to reason about.

I see little reason why you would want a context for transferring the same amount between the same accounts once again. Which was my second point. Why is the reference to the current important when the execution is done?
I returned a new TransferMoney context to give some indication to others reading the code that after calling Source.withdraw() and Destination.deposit(), the state of the current TransferMoney context is now outdated.

I think this is one reason why it's helpful if roles are allowed in top-level functions, without the requirement of creating a stateful Context object. Like in our Javascript implementations:

function TransferMoney(src, dst, amt) {
    ...
    role Source {...}
    ...
}


But even then, using immutable Account objects seems like an avenue for bugs, at least in a language with C-like syntax. Suppose a new programmer adds a new line to the TransferMoney context, after the transfer is complete:

Source.withdraw();  //returns new Account object
Destination.deposit(); 
//returns new Account object
...
Source.getBalance();


...They would be getting the old balance, not the new balance. I think that's surprising given the way the above code is written.

James O Coplien

unread,
Dec 23, 2015, 4:50:28 AM12/23/15
to object-co...@googlegroups.com

Den 23/12/2015 kl. 01.40 skrev Matthew Browne <mbro...@gmail.com>:

I think this is one reason why it's helpful if roles are allowed in top-level functions, without the requirement of creating a stateful Context object. Like in our Javascript implementations:


Hmmm. I’ll add it to my wish list.

Should we be keeping track of these ideas for trygve in GitHub?

Egon Elbre

unread,
Dec 23, 2015, 5:38:02 AM12/23/15
to object-composition
You can add specific labels for such e.g. "Feature" or "Wishlist" or "Idea":



Matthew Browne

unread,
Dec 23, 2015, 8:18:58 AM12/23/15
to object-co...@googlegroups.com
What if you could omit the 'new' keyword and it would run the constructor and automatically destroy the Context instance after it finished executing? So for a Context with a single trigger method, you could do:

TransferMoney(source, dest, 10.0);

instead of:

var transfer = new TransferMoney(source, dest, 10.0);
transfer.run();


So the public TransferMoney method in the TransferMoney context would now have a dual meaning; it would be a constructor if called with new, and otherwise would be the default method that runs when you invoke the Context itself. It could also return a value, e.g.:

int returnValue = MyContext();

The thing I like about doing it this way is that there's still just one kind of declaration for Contexts -- context. One thing that bugs me just a bit about my TypeScript implementation (and upcoming JS source transformation implementation...more on that soon) is that there are two ways of declaring Contexts - the context keyword and the function keyword. In any case it would be nice to have the word 'context' included somewhere when declaring both kinds of Context.

So yeah, add it to the wish list :)

rune funch

unread,
Dec 23, 2015, 8:37:36 AM12/23/15
to object-co...@googlegroups.com

2015-12-23 1:40 GMT+01:00 Matthew Browne <mbro...@gmail.com>:
I think that's surprising given the way the above code is written.

Sure, if you have a preconceived notion that data objects by default are mutable. If you know they are not it's very straightforward and have no surprises. It is said about FP programming that when it compiles your done. I'm not arguing that we should skip OO for FP but stressing that side-effect free programming makes it easier to reason about what goes on

rune funch

unread,
Dec 23, 2015, 8:40:05 AM12/23/15
to object-co...@googlegroups.com
2015-12-23 14:18 GMT+01:00 Matthew Browne <mbro...@gmail.com>:
What if you could omit the 'new' keyword and it would run the constructor and automatically destroy the Context instance after it finished executing? So for a Context with a single trigger method, you could do:

TransferMoney(source, dest, 10.0);

instead of:

var transfer = new TransferMoney(source, dest, 10.0);
transfer.run();


So the public TransferMoney method in the TransferMoney context would now have a dual meaning; it would be a constructor if called with new, and otherwise would be the default method that runs when you invoke the Context itself. It could also return a value, e.g.:

int returnValue = MyContext();

The thing I like about doing it this way is that there's still just one kind of declaration for Contexts -- context. One thing that bugs me just a bit about my TypeScript implementation (and upcoming JS source transformation implementation...more on that soon) is that there are two ways of declaring Contexts - the context keyword and the function keyword. In any case it would be nice to have the word 'context' included somewhere when declaring both kinds of Context.

So yeah, add it to the wish list :)
 
Quite some time ago we had a discussion of functors and context. I said then that I think a functor is a special case of a context (the special case you desribe) where there's only one possible entry point to the network of interconnected objects. So a generalized version where a functor is a context with one entry point would be neat if you ask me :) 

James O Coplien

unread,
Dec 23, 2015, 10:44:56 AM12/23/15
to object-co...@googlegroups.com

Den 22/12/2015 kl. 17.14 skrev Matthew Browne <mbro...@gmail.com>:

...So now that you mention it, it is possible. But I don't see how that makes the code easier to reason about.

Very understandable. It took me years of work with dataflow architectures to really appreciate their power. And in some large degree, what we’re talking about here looks like a single-thread dataflow machine.

You can actually prove, with a capital P, that these programs are more easily analyzable — that is, that you can derive properties about them with less computational power — than stateful programs. In the extreme then there are no states at all, and then you don’t have to worry about an object playing multiple Roles. My earlier research was exploring much more highly contextualized benefits such as the ability to update programs on-the-fly. That starts to make time part of the spatial geometry that you can reason about with your right brain, which has a lot more power to scale than the left brain does.

As human beings, our ability to navigate a 2.5-dimensional space is much more powerful than our ability to reason about time. State is fundamentally tied to time. If there is no change (in time) there is no state — only value. Children grok geometry almost at birth but it’s six months to a year before they can even appreciate causality. This suggests that more of the temporal domain of reasoning is learned than the spatial dimension. (http://www.slideshare.net/Avisi_ASAS/jim-coplien-asas-2014)

It was exactly this kind of work with the psychology of children that is on the edges of Piaget’s work, which in turn was a major moving force behind Kay’s work on object-oriented programming. Perhaps his early musings were more driven by Lisp and its functional nature than Smalltalk would become (Smalltalk certainly has many of the engineering features of Lisp, even though it dumped its computational model.) 

And we have an advantage over Kay. Piaget always thought that procedural memory emerged early, with declarative memory coming later. Later psychological research has proven Piaget wrong. So a declarative style — which is what Rune is advocating — is much more fundamental to our mental models (or perhaps meta-models) than time is.

There is of course a dance between the state of our implementations and their functionality. What is evil is when the states are hidden. We sometimes call these side-effects. Of course side-effects can also be visible, but most of them are not, and when they are, they cause us to try to think of two different things at once. A system with hidden state is said to be modal if the state affects how the system behaves. Raskin believed there were only two evils to be avoided in computer design: modality, and offering the user multiple ways to do the same thing (violating monotony). State is problematic; hidden state is evil. Software engineers like to make themselves feel good by “encapsulating” state in objects. It’s hard. It’s sustaining an illusion, using a digital machine to simulate an analog machine. Illusions are difficult to sustain.

Declarative, functional and applicative languages solve this the same way physicists deal with time: you make t a variable just like x, y, and z axis dimensions are. You turn time into space.

I have long been fascinated by this notion and have made an investment into studying human models of time. A great book on this is Hall’s The Dance of Life, which will completely blow your mind with respect to what time is. It looks at notions of time across culture. (Just to be fair I’ve also been exploring cultural models of space. They’re even more bizarre. Ideas like the Earth being on the back of a turtle — which gives whole new meaning to “up” and “down” — are not entirely dead. Some Indian traditions have a cosmological model reminiscent of Truman’s world in The Truman Show.) One place that particularly fascinates me is Japan, where the dichotomy between space and time is much less stark. They have a concept called ma that can be viewed as “interval”  but there is also a notion of synchronization, and of space, and of pause, and of position, it in. (Each comma in this sentence is maybe a kind of “ma.”) It figures important in kabuki theatre. But it’s not a $100 word — it’s part of common experience and everyday life.

The Japanese are programmed in Lisp whereas the Europeans are programmed in FORTRAN.

So I think teaching Japanese children to program can build on some powerful concepts that are absent in the “Western world.”

And it all comes down to understanding the limitations of state: a Western notion of Yes-No, compatible with a digital engineering view. The real world is not so demarcated in its business processes, but is instead driven by the instinctive operational models that Kay mentioned again and again in his early works.
Reply all
Reply to author
Forward
0 new messages