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

Feature: scoped_dictionary #71

Open
yrashk opened this issue Feb 17, 2017 · 12 comments
Open

Feature: scoped_dictionary #71

yrashk opened this issue Feb 17, 2017 · 12 comments

Comments

@yrashk
Copy link
Contributor

yrashk commented Feb 17, 2017

Introduced through #67

Problem: implementing words without subwords is difficult

Technically speaking, loaded words can define their own
words but they will leak into the remainder of the program,
which less than ideal.

Using stack alone requires a significant amount of juggling
that makes writing code incredibly frustrating. I personally
believe that the value of stack based programming languages
is in concatenative abilities (composition via stack), not
just being able to do everything by juggling items in the
stack.

Solution: make all SETs and DEFs done within any closure
local to that closure.

This means that if eventually we'll need to do code injection
that's not injecting what effectively amounts to closures,
we'll need to have a separate pass result type that can
indicate that.

@yrashk
Copy link
Contributor Author

yrashk commented Feb 17, 2017

Additional thought: at least in the current implementation, juggling values on the stack is somewhat more efficient in terms of allocations required. Values moving around stack aren't allocated, just referenced. Words are based on code injection which requires some allocation

@yrashk
Copy link
Contributor Author

yrashk commented Feb 18, 2017

An important downside of this feature: one won't be able to retrieve a bunch of definitions from the storage and EVAL them to define a number of words

@yrashk
Copy link
Contributor Author

yrashk commented Feb 18, 2017

PR has been updated to reduce the scope and implement a new word called EVAL/SCOPED

@yrashk
Copy link
Contributor Author

yrashk commented Feb 18, 2017

Gated feature merged

@yrashk
Copy link
Contributor Author

yrashk commented Feb 21, 2017

While playing further with it, I discovered one more edge case that's not great about it. Let me think about it a bit more.

Basically, there's a situation when we pass closures between scopes. This is sneaky:

CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   [c closure EVAL [c iterator EVAL] [0] IFELSE] DOWHILE] EVAL/SCOPED.
?CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   c [?CURSOR/CUR closure EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.

will fail on this:

PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1] 'CURSOR/NEXT? ?CURSOR/DOWHILE] READ
Error: "Invalid value" 0x1a17746573746b65790000000014a454200eded6f0000000000101 0x03

However, if I change the closure name like this:

?CURSOR/DOWHILE : ['iterator SET 'closure_ SET 'c SET
                   c [?CURSOR/CUR closure_ EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.

then everything is fine:

PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1] 'CURSOR/NEXT? ?CURSOR/DOWHILE] READ
0x746573746b65790000000014a454200eded6f000000000 0x01 0x746573746b65790000000014a454200f336b4800000000 0x02 0x746573746b65790000000014a454200f79af9000000000 0x03 0x746573746b65790000000014a454200fb5513000000000 "Hello"

It basically comes down to one very interesting question: how do we pass scoped words inside of closures... because once we pased from ?CURSOR/DOWHILE to CURSOR/DOWHILE, CURSOR/DOWHILE overrode 'closure

@yrashk
Copy link
Contributor Author

yrashk commented Feb 21, 2017

What can we do about this?

  1. Keep at as is, but if you know you're passing a closure into a word that has its own scope, check if you are not going to clash.
  2. Implement a word that would replace dictionary-based words with their values ("expand")
  3. ?

@yrashk
Copy link
Contributor Author

yrashk commented Feb 21, 2017

I think have a decent solution for this. Just like we have EVAL that evaluates in the curren scope, EVAL/SCOPED evaluated in a new scope, we should have EVAL/UNSCOPED that evaluates in the parent scope. It's not perfect though, as (I think) if an interim scope just passes the closure through, then it might not work. Need to check

@yrashk
Copy link
Contributor Author

yrashk commented Feb 21, 2017

I am still not 100% happy with EVAL/UNSCOPED as this would require a ceremony to pass closure by names. I am leaning towards stating that the only safe way to pass a named closure is to get its value first, so it can be passed by value.

@yrashk
Copy link
Contributor Author

yrashk commented Feb 21, 2017

Current idea: enable unwrapping syntax for the text form:

[1 `closure] => [1] closure CONCAT [] CONCAT

yrashk added a commit to yrashk/PumpkinDB that referenced this issue Feb 22, 2017
Basically, there's a situation when we pass closures between scopes. This is sneaky:

```
CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   [c closure EVAL [c iterator EVAL] [0] IFELSE] DOWHILE] EVAL/SCOPED.
?CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   c [?CURSOR/CUR closure EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.
```

will fail on this:

```
PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1]
'CURSOR/NEXT? ?CURSOR/DOWHILE] READ Error: "Invalid value"
0x1a17746573746b65790000000014a454200eded6f0000000000101 0x03
```

However, if I change the closure name like this:

```
?CURSOR/DOWHILE : ['iterator SET 'closure_ SET 'c SET
                   c [?CURSOR/CUR closure_ EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.
```

then everything is fine:

```
PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1]
'CURSOR/NEXT? ?CURSOR/DOWHILE] READ
0x746573746b65790000000014a454200eded6f000000000 0x01
0x746573746b65790000000014a454200f336b4800000000 0x02
0x746573746b65790000000014a454200f79af9000000000 0x03
0x746573746b65790000000014a454200fb5513000000000 "Hello"
```

(See PumpkinDB#71)

It basically boils down to the fact that `closure` here is passed
by name, not by value and is being subsequently shadowed with
another `closure`

Solution: add syntax sugar for "unwrapping" word values from
closures:

```
[?CURSOR/CUR `closure EVAL]
```
yrashk added a commit to yrashk/PumpkinDB that referenced this issue Feb 22, 2017
Basically, there's a situation when we pass closures between scopes. This is sneaky:

```
CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   [c closure EVAL [c iterator EVAL] [0] IFELSE] DOWHILE] EVAL/SCOPED.
?CURSOR/DOWHILE : ['iterator SET 'closure SET 'c SET
                   c [?CURSOR/CUR closure EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.
```

will fail on this:

```
PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1]
'CURSOR/NEXT? ?CURSOR/DOWHILE] READ Error: "Invalid value"
0x1a17746573746b65790000000014a454200eded6f0000000000101 0x03
```

However, if I change the closure name like this:

```
?CURSOR/DOWHILE : ['iterator SET 'closure_ SET 'c SET
                   c [?CURSOR/CUR closure_ EVAL] iterator CURSOR/DOWHILE] EVAL/SCOPED.
```

then everything is fine:

```
PumpkinDB> [CURSOR 'c SET c "testkey" CURSOR/SEEK? DROP c [UNWRAP  1]
'CURSOR/NEXT? ?CURSOR/DOWHILE] READ
0x746573746b65790000000014a454200eded6f000000000 0x01
0x746573746b65790000000014a454200f336b4800000000 0x02
0x746573746b65790000000014a454200f79af9000000000 0x03
0x746573746b65790000000014a454200fb5513000000000 "Hello"
```

(See PumpkinDB#71)

It basically boils down to the fact that `closure` here is passed
by name, not by value and is being subsequently shadowed with
another `closure`

Solution: add syntax sugar for "unwrapping" word values from
closures:

```
[?CURSOR/CUR `closure EVAL]
```
@yrashk
Copy link
Contributor Author

yrashk commented Feb 23, 2017

#108 would resolve this issue

@yrashk
Copy link
Contributor Author

yrashk commented Feb 23, 2017

Graduated the feature in #103. Still tracking as the feature gate hasn't been dropped, simply moved to default.

@omarkj omarkj added this to the 0.2.0 ("Wee-Be-Little") milestone Feb 26, 2017
@yrashk
Copy link
Contributor Author

yrashk commented May 16, 2017

I suggest keeping this feature-gated until we see what the future compilation technique will bring in in terms of scoping. Thoughts?

@yrashk yrashk removed this from the 0.2.0 ("Wee-Be-Little") milestone May 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants