#848 Remove sys::Context

tactics Wed 2 Dec 2009

Would it be possible to override Context.trap so that variables can be accessed with the -> operator?

It seems that in almost all cases, developers are going to use variable names that are legitimate Fantom identifiers. To me, it seems easier to type cx->counter than cx["counter"]. Few characters, one less shift, and I don't have to worry about accidentally typing cx['counter'] by mistake (which I do all the time in Fantom, coming from Javascript/PHP/Python).

So something like

a := Actor(ActorPool()) |msg, cx|
  {
    if (msg == "current") return cx["counter"]
    if (msg == "reset") { cx["counter"] = 0; return null }
    cx["counter"] = 1 + cx["counter"]
    return null
  }

Could be typed up as

a := Actor(ActorPool()) |msg, cx|
  {
    if (msg == "current") return cx->counter
    if (msg == "reset") { cx->counter = 0; return null }
    cx->counter = 1 + cx->counter
    return null
  }

And there'd be just a little less noise.

brian Wed 2 Dec 2009

I dig it - done!

Sometimes I wonder if that should be the default behavior for Map (or if we should have some class that lets you use a map like a Python/JavaScript associative array)

brian Wed 2 Dec 2009

Actually what about this idea:

  • Rename Context to something more general purpose
  • Remove Context.actor to make it a stand alone piece of functionality
  • Finish up trap support to handle funcs (Python/JavaScript style)

Then we'd have nice associative array class which could be used with -> operator:

obj = Something()
obj->first = "Brian"
obj->last  = "Frank"
obj->full  = |self->Str| { self->first + " " + self->last }

What do you guys think of that?

What would be a good name for such a class?

MoOm Wed 2 Dec 2009

I think "Dynamic" might be a good name for such class (this name comes from HaXe, where there is a "Dynamic" class that does exactly that).

tcolar Wed 2 Dec 2009

+1 like the idea. Name: DynArray ?

tactics Wed 2 Dec 2009

Maybe Dyn or DynObj instead of Dynamic. The word "dynamic" has a lot of baggage that comes with it, and if we shorten it, that baggage won't hold on so tightly.

Or maybe a totally different word. What about Store? It makes sense in the Actor case, because you "store" your state there. Maybe Stash.

Where would you use it other than with Actors?

jodastephen Wed 2 Dec 2009

obj->full  = |self->Str| { self->first + " " + self->last }

So why are you calling the Str method on self?

OK, ok, I know that is a closure return type definition, but boy does it look confusing. Maybe that syntax shouldn't be doing double duty?

qualidafial Thu 3 Dec 2009

There's also Expando from JavaScript if I remember correctly.

brian Thu 3 Dec 2009

I was thinking more along the lines of a "collections" sort of class, since it will do double duty. Consider the proposed new Actor API:

new make(ActorPool, |Obj?, Dyn->Obj?|)

Things like Dyn or Dynamic don't seem to work that well. BTW, we should use this class for web::WebReq.stash too.

Some ideas: Bag, AList, AArray, Array?, Assoc, Rec

Seems like we should be able to find some word that implies general purpose Str to Obj? map.

DanielFath Thu 3 Dec 2009

How about Dictionary or Dict? Con it sounds like Python and but its meaning is about right - a string tied to context.

PS when are you gonna add Set?

PPS. Is it just me or should Dyn->Obj? be a child of Map?

freddy33 Thu 3 Dec 2009

I used AttributeBag or AttrBag in some App. For me, Dictionary kind of imply Str:Str maps.

brian Thu 3 Dec 2009

Actually I really dig Dict (and from a Java 1.0 perspective it was the original Map superclass).

PS when are you gonna add Set?

I guess I've never really felt a strong desire for it b/w List and Map. So I don't think it is a core sys thing. But now that we have a util pod we could start putting collection helper classes in there.

PPS. Is it just me or should Dyn->Obj? be a child of Map?

I agree from a pure OO model, but I think delegation is the right model here since Map is such a special thing in Fantom. Subclassing List or Map would be a can of worms.

So let's make it Dict - a general purpose Str:Obj? map that overrides trap so that items can be accessed with -> operator.

brian Thu 3 Dec 2009

Promoted to ticket #848 and assigned to brian

brian Thu 3 Dec 2009

Renamed from Context.trap to sys::Dict

DanielFath Thu 3 Dec 2009

I guess I've never really felt a strong desire for it b/w List and Map. So I don't think it is a core sys thing. But now that we have a util pod we could start putting collection helper classes in there.

Yeah but I really think {2.0, "String", 2} or {{2.0, "String", 2}} would be an awesome way to make sets and I'm unsure whether you can do this from a non-sys library.

I used AttributeBag or AttrBag in some App. For me, Dictionary kind of imply Str:Str maps.

First there is a reference to Python's dict (which unfortunately is Fantom Map equivalent) and secondly dictionary are more often Str:Str[] since words often have more than one meaning.

andy Thu 3 Dec 2009

I've seen Dict used in this context before, so its probably ok. Though seems like it might be simpler to just make that the trap behavior on Map. What are the negatives to that approach?

tactics Thu 3 Dec 2009

Though seems like it might be simpler to just make that the trap behavior on Map.

I'm leaning towards this. It's neat, but it doesn't seem distinct enough from Map.

It reminds me of an issue I always have in PHP when I haven't used JSON in a while. I will always try:

$json = '{"foo": "bar", "baz": null}';
$data = json_decode($json);
echo $data["foo"];

But that's incorrect! Every time, I forget, it needs to be:

$json = '{"foo": "bar", "baz": null}';
$data = json_decode($json);
echo $data->foo;

It's frustrating, because the two syntaxes mean essentially the same darned thing. Forcing me to use one syntax over another is just splitting hairs.

andy Thu 3 Dec 2009

It's frustrating, because the two syntaxes mean essentially the same darned thing. Forcing me to use one syntax over another is just splitting hairs.

I agree, and related, requiring a valid identifier to be used for Dict would get annoying real quick. I use . and - heavily right now in those contexts. It wouldn't be the end of the world if I had to use camel case or something, but if Map supported -> access, it would be a non-issue.

brian Thu 3 Dec 2009

It wouldn't be the end of the world if I had to use camel case or something, but if Map supported -> access, it would be a non-issue.

I think the notion of requiring Dict to have it keys as valid identifiers is something to debate. Making them identifiers has potentially lots of nice future proofing for the things you can do that data and provides a nice guarantee of what the contract really means. The only negative is really you have to use camel case instead of dots, dashes, etc.

It's frustrating, because the two syntaxes mean essentially the same darned thing. Forcing me to use one syntax over another is just splitting hairs.

The [] syntax would be available to both Map and Dict. It is just a question of the -> syntax being different.

I've seen Dict used in this context before, so its probably ok. Though seems like it might be simpler to just make that the trap behavior on Map. What are the negatives to that approach?

The huge downside is that you can't use -> on any Map method, so simple things like this would no longer work:

map := runSomeTest
verify(map->isEmpty)

But wrapping the map in a Dict we can maintain the two namespaces (Map's slots vs data slots). Ideally you'd want to reserve one identifier to dynamically get the Dict's map (like Python does with double underbars), but maybe you just have to cast to Dict first.

DanielFath Thu 3 Dec 2009

Nvm. Brian just posted an explanation.

andy Thu 3 Dec 2009

I think my problem here is we are basically creating two Map constructs (which is a mistake IMO) - where the problem we're trying to solve is creating anonymous/dynamic types. Yeah, thats basically the same thing, but going down the path of Dict seems the wrong direction. I think we need to stew on this a bit more before we commit any changes.

brian Thu 3 Dec 2009

Just to put things back into perspective - we already have an existing Context class, we are merely renaming it and making it more general purpose.

If the debate is about getting rid of Context all together and just using Str:Obj? then that is another matter.

qualidafial Thu 3 Dec 2009

The huge downside is that you can't use -> on any Map method, so simple things like this would no longer work:

Wouldn't this also hose map deserialization?

tompalmer Thu 3 Dec 2009

OK, ok, I know that is a closure return type definition, but boy does it look confusing. Maybe that syntax shouldn't be doing double duty?

I agree that the overloaded meaning of -> can be confusing.

mwanji Thu 3 Dec 2009

Not sure it's really relevant, but Gilad Bracha's latest blog post is called Objects Are Not Hash Tables :)

brian Sat 5 Dec 2009

This is a good discussion. There are obviously lots of sticky issues regarding the distiction between Dict and Str:Obj?.

I don't think we really need to solve the dynamic object thing immediately. However we have many cases where the notion of a Str:Obj? comes up and we should provide a consistent solution. Today I am aware of:

The Context class largely exists as only a wrapper for Str:Obj?. WebSession is larger a wrapper, but does provide some extra functionality. But in most other cases we just use a raw Str:Obj? map. I am not sure what a good rule of thumb should be.

Couple options I see:

  1. Use raw Str:Obj? whenever possible, and avoid wrappers. In this option I would say Context should go away.
  2. Use wrapper like Dict consistently. This would replace Context, and probably become a super class for WebSession. This option would require some special support for Fantom and JSON serialization. But that gets into tricky issues. Does JSON require Dict, or allow both Dict and Str:Obj??

Votes between those two options? Other ideas?

DanielFath Sat 5 Dec 2009

I don't see a reason to introduce a wrapper for Str:Obj? so

+1 to first.

andy Sat 5 Dec 2009

I'm not fond of creating a new map construct, so I think we need to solve this with the existing Map type. If wrappers can be avoided, thats great.

Though WebSession looks fine as is. It has conveniences for get and set, but the map is still a proper Str:Obj? field, and the other fields seem required. This is the right design IMO.

Context, however, seems like that can be turned into a straight Str:Obj? map (and free up that useful term). The Context.actor field seems better served as Actor.current anyways.

lbertrand Sun 6 Dec 2009

+1 for using basic Map if nothing added by the wrapper

jodastephen Sun 6 Dec 2009

I don't believe that standard Map objects should use -> to access their values. But I do believe that -> access is useful in certain circumstances.

As such, I support the Dict class as an alternate Str:Obj?. (There are times when extra classes enhance APIs, and this is one of those times)

freddy33 Mon 7 Dec 2009

I wanted to try something (but lack of time lately), can Dict be a mixin? I have the same issue trying to create a Matrix as a mixin of a List of ( Int, Float, Complex, ... )

DanielFath Mon 7 Dec 2009

Freddy33 I've been making the same thing. My best bet is to make Matrix a wrapper for List, have a constructor that takes type and dimensions, and check using reflection whether or not the type fits or not (If it is Num then it is OK, otherwise check whether it has plus, negate, mult and div).

brian Mon 7 Dec 2009

Let's wrap up this up by saying convention is to not wrap Str:Obj? unless the class provides real value (such as WebSession).

So that means we want to remove the sys::Context class.

But what to do with Actor API? There are two options:

  1. change Context param to Str:Obj? map
  2. remove param entirely and rely on sys::Actor.locals

Opinions?

lbertrand Mon 7 Dec 2009

I really don't see the added value of sys::Context above the standard map Str:Obj?.

So I will vote for relying only on sys::Actor.locals

andy Mon 7 Dec 2009

I don't have a whole lot of experience with the Actor API - but the cx param seems like it can be cleanly modeled using Actor.locals. So I vote #2.

qualidafial Mon 7 Dec 2009

It does seem like sys::Actor.locals and sys::Context are duplicate APIs.

I vote for #2: remove sys::Context in favor of sys::Actor.locals.

Edit: clarify my vote

brian Tue 8 Dec 2009

Renamed from sys::Dict to Remove sys::Context

brian Fri 18 Dec 2009

Ticket resolved in 1.0.48

I wasn't able to implement this change and keep the old behavior as deprecated. So it just a clean breaking change:

  • sys::Context is removed
  • Actor.receive just takes one parameter

Replace use of Context with Actor.locals.

Note that the version in hg tip the constructor still takes a two param func, but that will be fixed right before the build.

Login or Signup to reply.