Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undo works incorrectly in the Playground #2814

Open
mrakgr opened this Issue Mar 14, 2019 · 0 comments

Comments

Projects
None yet
1 participant
@mrakgr
Copy link

mrakgr commented Mar 14, 2019

I've checked this bug in Pharo 7 and Pharo 8. Here is how to replicate it.

1.
2.
3.
4

First write out the above or paste it into the Playground. Then delete the second line like so.

1.

3.
4

Then Do it all and Go using the button or Ctrl+Shift+g. Do not select all + right click. Then press Ctrl+z to undo.

For me what happens is this.

1.

Everything past the second line gets erased rather than the second line being undone..

mrakgr added a commit to mrakgr/Pharo-Examples that referenced this issue Mar 14, 2019

"9:30am. https://news.ycombinator.com/item?id=10071681
Now I am just wasting time with threads like these. Let me see if I got an answer to the question I asked yesterday.

9:35am. curtis: 
"I suspect that a lot of the impediment to JITing Ruby and Python effectively was due to large and important libraries (standard and third-party) being written in C using interfaces that were not JIT-friendly. JavaScript in the browser also depends on C/C++ interfaces to important functionality, but the entire stack for each engine was controlled by a single organization, and was always released as a unit (the web browser). I think this largely eliminated library inertia (or whatever you want to call it) as a problem when replacing a JavaScript engine.

The other advantage JavaScript had was that there were large, well-funded organizations (notably Google and Mozilla) competing on performance. Python and Ruby were always community projects and they had a strong emphasis on maintaining backwards compatibility with a large and diverse ecosystem, and there wasn't a lot of demand for faster implementations."

chriseaton: 
"JavaScript is a relatively small and simple language with relatively constrained semantics that allow it to be implemented relatively simply.

Ruby and Python are the opposite of that. Ruby and Python are I'd say literally a thousand times more complicated to compile than JavaScript."

Interesting answers. I find the second one more likely.

https://news.ycombinator.com/item?id=10099304
https://news.ycombinator.com/item?id=10071681

Let me finish the Smalltalk threads and then I will start. I am just addicted to this.

9:40am. "I was very enthusiastic about Smalltalk in the late 80's when I got Digitalk's System V to play with. And one thing torpedoed its use for me - local variables in code blocks are local to the code object, not the execution stack, so you cannot use them for instance data in multiple instances of persistent State Machines. I thought this was a bug, but Digitalk told me no, it's in the language specification. Since that is my preferred way of achieving hard Real Time event driven concurrency, I could no longer use it and switched to hand-rolled OOP in C.
Why not C++? you might ask. The year was 1988. I needed to run on Macs as well as PCs. The only company advertising C++ for Mac at the time was AT&T (the purely Preprocessor implementation). When I called them to order a copy they said "Really? C++ for Mac? You're only the sixth person ever to ask for it, so we have not done it yet". At the same time, Objective C was similarly not available in Windows."

Interesting note from 4 years ago.

9:45am. "Sigh. Nothing killed Smalltalk. It's not dead. Neither is Scheme. Yeah, both of those languages have pretty small communities, but that's viable in the Internet Age.
Heck, even Self, which nobody ever used for actual shipping software (as far as I know), still has some life in it. The latest release was last year and runs on Linux, Mac OS X. (What, no Solaris support?) http://blog.selflanguage.org/2014/01/12/self-mallard-4-5-0-r...

Compared to Self, Smalltalk and Scheme are downright mainstream, and used in all sorts of production software.

This is important if you're planning on inventing a new programming language. The chances that you create the next Javascript or Java are slim to none. Those languages are platforms that are backed by large companies. Languages invented by enthusiastic geeks can succeed, but they don't take over the world. Even when success does come, it's after decades as niche languages with tiny communities.

If you consider Smalltalk and Scheme dead, be prepared to have your language be stillborn."

10am. Fuck me, how long will I read the HN threads? Let me start the tutorial. I guess when I start being certain, my contrarianism kicks in.

10:05am. Done with the Trachel chapter. Let me move to the next one.

10:25am. Had to do some chores ahead of time it seems. Let me resume.

10:40am.

```
	v := RTView new.
	shape := RTBox new color: Color blue trans.
	elements := shape elementsOn: (1 to: 50).
	v addAll: elements.
	elements @ RTPopup.

	RTEdgeBuilder new
		view: v;
		objects: (1 to: 50);
		connectFrom: [ :i | i // 3 ].

	RTTreeLayout on: elements.
	v
```

Hmmm, ok. I sort of see it.

The playground is buggy, if I erase a line and then run the program, the undo will give a wrong result.

Is this problem in Pharo 8?

Yeah, it is. Let me report it.

10:55am. pharo-project/pharo#2814

I opened an issue for this.

11:05am. Ok, stop reading random Pharo Github issues. Let me move on.

```
	v := RTView new.
	shape := RTBox new color: Color blue trans.
	elements := shape elementsOn: (1 to: 50).
	v addAll: elements.
	elements @ RTPopup.

	RTEdgeBuilder new
		view: v;
		objects: (1 to: 50);
		connectFrom: [ :i | i // 3 ].

	RTTreeLayout on: elements.
	v
```

Let me paste this again. I am really not too comfortable with how mutable the process of constructing models is, but I'll defer judgment for later.

11:15am. I am finally starting to get into this. I am starting to form a mental model of the above fragment. Let me continue to the next example.

11:30am. Wow, it sucks just how buggy undo is.

11:35am.

```
	"Processing a small TSV table"
	tab := RTTabTable new input: 
	'id	value1	value2	category	parent
	1	10	20	A	1
	2	5	12	B	1
	3	8	17	A	1
	4	9	13	D	3
	5	30	30	D	3'.
	tab removeFirstRow.
	"Converting columns into integer"
	tab convertColumnsAsInteger: #(1 2 3 5).
	tab convertColumn: 5 to: [ :entry | tab values at: entry fifth ].

	v := RTView new.
	colorNormalizer := RTMultiLinearColorForIdentity new 
				objects: (tab values collect: #fourth) asSet sorted; 
				command: #fourth.

	shape := RTBox new
				width: #second;
				height: #third;
				color: colorNormalizer.
	elements := shape elementsOn: tab values.
	v addAll: elements.

	elements @ (RTPopup new text: [ :entry | 
		'id = ', entry first asString, String cr, 
		'value1 = ', entry second asString, String cr,
		'value2 = ', entry third asString, String cr ]).

	elements @ (RTLabeled new text: [ :entry | entry first ]).

	RTEdgeBuilder new
		view: v;
		objects: tab values;
		connectFrom: [ :entry | entry fifth ].

	RTHorizontalTreeLayout new
		verticalGap: 30; on: elements.
	v  
```

Do I really have to take the `values` of a `tab`? It seems I do.

11:40am. Now this example works, but the colors are not correct. There should be 3 of them, and there are only 2 of them in the playground.

...Agh, with Undo bugs and redo not existing, it is beyond annoying to work in the Playground.

I am not sure why the color normalizer is not working.

11:45am. Maybe I'll figure it out later, it is not that important.

Let me move on.

```
RTMultiLinearColorForIdentity new 
				objects: (tab values collect: #fourth) asSet sorted; 
				command: #fourth.
```

No actually, let me explore this thing.

```
RTMultiLinearColorForIdentity new objects: #(A B C).
```

12pm. Ah, I have no idea why the colors are not working. The `RTMultiLinearColorForIdentity` instance itself seems to be giving correct results. Then what is the problem?

Ah, let me try something. I'll normalize it directly.

```
	colorNormalizer := RTMultiLinearColorForIdentity new 
				objects: (tab values collect: #fourth) asSet sorted.
	tab convertColumn: 4 to: [ :each | colorNormalizer colorOf: each].
```

Let me do this.

```
	"Processing a small TSV table"
	tab := RTTabTable new input: 
	'id	value1	value2	category	parent
	1	10	20	A	1
	2	5	12	B	1
	3	8	17	A	1
	4	9	13	D	3
	5	30	30	D	3'.
	tab removeFirstRow.
	"Converting columns into integer"
	tab convertColumnsAsInteger: #(1 2 3 5).

	v := RTView new.
	colorNormalizer := RTMultiLinearColorForIdentity new 
				objects: (tab values collect: #fourth) asSet sorted.
	tab convertColumn: 4 to: [ :each | colorNormalizer colorOf: each].
	shape := RTBox new
				width: #second;
				height: #third;
				color: #fourth.
	elements := shape elementsOn: tab values.
	v addAll: elements.

	elements @ (RTPopup new text: [ :entry | 
		'id = ', entry first asString, String cr, 
		'value1 = ', entry second asString, String cr,
		'value2 = ', entry third asString, String cr ]).

	elements @ (RTLabeled new text: [ :entry | entry first ]).

	RTEdgeBuilder new
		view: v;
		objects: tab values;
		connectFrom: [ :entry | tab values at: entry fifth ].

	RTHorizontalTreeLayout new
		verticalGap: 30; on: elements.
	v  
```

Even this sort of normalization fails. That means RTBox is at fault.

```
"[ :anElement | aValueOrAOneArgBlock rtValue: anElement model ]"
self
```

Ah, it seems it might not be taking a symbol. Height or width, one of them should not do it either. What shoddy construction.

12:10pm. I narrowed it down a bit. The overall design of this is so convoluted.

```
	RTEdgeBuilder new
		view: v;
		objects: tab values;
		connectFrom: [ :entry | tab values at: entry fifth ].
```

The objects here in particular. Do they have to be tab values?

```
	RTEdgeBuilder new
		view: v;
		connectFrom: [ :entry | tab values at: entry fifth ].
```

No. When done like this the sensible thing will be done.

```
	"Processing a small TSV table"
	tab := RTTabTable new input: 
	'id	value1	value2	category	parent
	1	10	20	A	1
	2	5	12	B	1
	3	8	17	A	1
	4	9	13	D	3
	5	30	30	D	3'.
	tab removeFirstRow.
	"Converting columns into integer"
	tab convertColumnsAsInteger: #(1 2 3 5).

	v := RTView new.
	colorNormalizer := RTMultiLinearColorForIdentity new 
				objects: (tab values collect: #fourth) asSet sorted.
	tab convertColumn: 4 to: [ :each | colorNormalizer colorOf: each].
	shape := RTEllipse new
				width: #second;
				height: #third;
				color: #fourth.
	elements := shape elementsOn: tab values.
	v addAll: elements.

	elements @ (RTPopup new text: [ :entry | 
		'id = ', entry first asString, String cr, 
		'value1 = ', entry second asString, String cr,
		'value2 = ', entry third asString, String cr ]).

	elements @ (RTLabeled new text: [ :entry | entry first ]).

	RTEdgeBuilder new
		view: v;
		connectFrom: [ :entry | tab values at: entry fifth ].

	RTTreeLayout new
		verticalGap: 30; on: elements.
	v  
```

When I switch to `RTEllipse` and a different layout the same bug in the way colors are displayed persists. Either there is something wrong in the view or the `RTGroup` then.

12:15pm. Let me stop here. I need to eat. I'll move to the next problem. I'll revisit this when it comes time to trace they display of this."

mrakgr added a commit to mrakgr/The-Spiral-Language that referenced this issue Mar 18, 2019

"9:35am.
```
type Actions =
    | Pass
    | Bet

type Cards =
    | One
    | Two
    | Three

let rng = System.Random()

let knuth_shuffle (ar: _[]) =
    let swap i j =
        let item = ar.[i]
        ar.[i] <- ar.[j]
        ar.[j] <- item

    for i=Array.length ar - 1 downto 1 do swap (rng.Next(i+1)) i

let ar = [|One; Two; Three|]
knuth_shuffle ar; ar
```

The Knuth shuffle is easy enough. I am using the version I saw in the Pharo library here.

Let me move on.

```
compare One Three
```

Actually, I am quite surprised that this gives me -2. I thought that compare only gave -1,0 and 1. Quite interesting.

Maybe it only does that for degenerate unions.

9:50am.

```
type State =
    | Pass
    | PassPass
    | PassBet
    | PassBetPass
    | PassBetBet
    | Bet
    | BetPass
    | BetBet
```

Let me put this here for the time being.

I haven't decided what the states should be yet.

10:15am.

```
let normalize array =
    let temp, normalizing_sum =
        Array.mapFold (fun s x ->
            let strategy = max x 0.0
            strategy, strategy + s
            ) 0.0 array

    let inline f g = for i=0 to temp.Length-1 do temp.[i] <- g temp.[i]
    if normalizing_sum > 0.0 then f (fun x -> x / normalizing_sum)
    else f (fun _ -> 1.0 / float actions.Length)

let add_strategy_sum agent realization_weight x =
    let sum = agent.strategy_sum
    Array.iteri (fun i x -> sum.[i] <- sum.[i] + realization_weight * x) x
```

Now `normalize` will be optimized.

10:25am. Renaming is just so good in VS. It is amazing.

In terms of stability and ease of use, VS is actually better than Pharo's IDE. Pharo needs to take some lessons from it.

Pharo irks:
- Lack of dedent with Shift + Tab
- Tabs rather than spaces
- [Undo](pharo-project/pharo#2814)
- Autocomplete sinking
- [System browser sinking](pharo-project/pharo#2800)
- GToolkit crashing on delete
- Lack of variable popup in debugger
- Meta taking only half of the screen
- [Class revert does not revert methods](pharo-project/pharo#2853)
- All the buggy Roassal examples

I am just gathering some ammo in case I get challenged in the next PL monthly thread.

Note: Highlight my recent renaming experience in VS.

10:35am. Now, enough of that. Let me start work on the CFR function before I get distracted any further.

As expected this example is quite hard, mostly because the code in the paper is so crappy.

I am going to have to do it roughly and then I am going to have to do it cleanly. I am not sure why there aren't two nodeMaps, one for each player.

10:45am.

```
private double cfr(int[] cards, String history, double p0, double p1) {
    int plays = history.length();
    int player = plays % 2;
    int opponent = 1 - player;
    *Return payoff for terminal states*
    String infoSet = cards[player] + history;
    *hGet information set node or create it if nonexistant*
    *For each action, recursively call cfr with additional history and probability*
    *For each action, compute and accumulate counterfactual regret*
    return nodeUtil;
}
```

No, this is just so crappy. I cannot possibly abide by this. I will do it differently.

Let me just ask, is this example really intended to have two players or is it just a single player playing against itself?

10:55am.

```
if (plays > 1) {
    boolean terminalPass = history.charAt(plays - 1) == ’p’;
    boolean doubleBet = history.substring(plays - 2, plays).equals("bb");
    boolean isPlayerCardHigher = cards[player] > cards[opponent];
    if (terminalPass)
        if (history.equals("pp")) return isPlayerCardHigher ? 1 : -1;
        else return 1;
    else if (doubleBet) return isPlayerCardHigher ? 2 : -2;
}
```

I will have to express this in terms of pattern matching.

11am.

```
let cfr history (one : Semblance) (two : Semblance) =
    match history with
    | [Pass; Pass] -> if one.card > two.card then 1.0 else -1.0
    | [Pass; Bet; Pass] -> -1.0
    | [Pass; Bet; Bet] -> if one.card > two.card then 2.0 else -2.0
    | [Bet; Pass] -> 1.0
    | [Bet; Bet] -> if one.card > two.card then 2.0 else -2.0
    | _ ->
```

Something like this should be decent.

11:15am.

```
double[] strategy = node.getStrategy(player == 0 ? p0 : p1);
double[] util = new double[NUM_ACTIONS];
double nodeUtil = 0;
for (int a = 0; a < NUM_ACTIONS; a++) {
    String nextHistory = history + (a == 0 ? "p" : "b");
    util[a] = player == 0
        ? - cfr(cards, nextHistory, p0 * strategy[a], p1)
        : - cfr(cards, nextHistory, p0, p1 * strategy[a]);
    nodeUtil += strategy[a] * util[a];
}
```

This is so convoluted. I have no idea which player is supposed to act here. I am going to have to do it as originally intended.

Let me take off for a bit here."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.