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

Access to scope from imported functions? #1055

Closed
AlexMouton opened this issue Mar 1, 2018 · 7 comments
Closed

Access to scope from imported functions? #1055

AlexMouton opened this issue Mar 1, 2018 · 7 comments

Comments

@AlexMouton
Copy link

Hi Jos
Just another thought.
Can I access the scope from these functions I have imported into mathjs?
My circumstances may be a bit left-field, but I'd like to produce some side effects, but I don't have an opportunity to close over Scope when these functions are created.

I have a working pattern where I return a signal structure from the evaluation of the function, and collect those after evaluation, but this seems fragile.

No urgency from me but putting it all out there while its on my mind

Thanks
Alex

@josdejong
Copy link
Owner

Maybe what you're looking for is custom argument parsing using the rawArgs property?

http://mathjs.org/docs/expressions/customization.html#custom-argument-parsing

@WesleyKapow
Copy link

WesleyKapow commented Mar 28, 2020

I'm running in to a related issue. Initially I thought the function with rawArgs would work out but I see now that it is not getting the raw scope and instead is getting Object.assign({}, scope, args) (see: f6f7bd2#diff-0f51ca5cb1c91e563f1021231dfdc224R97). This kills usage of Proxy on a scope. It'd be nice if there was a clean way to just get the raw scope passed in... maybe to all functions as last argument?

As a work around I can simply nest my proxied scope an extra level and then prefix all references, e.g. scope.var instead of just var. That way the Object.assigns call keeps my Proxy. Less than ideal, but workable!

@josdejong
Copy link
Owner

That's an interesting case, using a Proxy. I think passing both scope and "rawScope" or something like that would complicate matters quite a bit. Just thinking aloud: maybe it is possible to pass a proxy instead, or pass a getFromScope and putInScope, which can then check args and scope consecutively. Also quite ugly though.

Just for my understanding: can you explain your use case where you need a Proxy?

@WesleyKapow
Copy link

Hmm ya I'm not sure of the best solution here. I am curious why args are being set in to the scope though via Object.assign({}, scope, args)? What is args here? And why is it needed if the purpose is receive the rawArgs?

Just for my understanding: can you explain your use case where you need a Proxy?

I'm using mathjs for a reactive expression evaluator. So when a value changes, the expression gets re-run. Wiring things up for my use has been tricky. Using a proxy allows me to listen in on what values are being referenced and wire up the reactivity. So for example, executing mathjs.evaluate("foo.bar * 10", proxyScope), I can observe the request for bar on foo and setup the needed watchers. In my case it's even more needed as foo.bar may not exist yet, and so my proxy lazily fetches the needed value. I'll definitely reach out when I have something to show :)

@josdejong
Copy link
Owner

If you define a function f and use it like in the following example:

const scope = {
  b: 5
}
math.evaluate('f(x) = x^2', scope)
const result = math.evaluate('b * f(3)', scope)

then, at the point function f is executed, it passes a scope containing b and f, and args contains the function variable x (having value 3 in the example). Since we do not want to pollute the provided scope with temporary values like x, we merge scope and args in a new object.

Thanks for explaining your use case. Is this "lazy fetching" async? (since that isn't really supported by mathjs, curious how that works). Just thinking aloud here: instead of using a proxy, you could also analyze what symbols are used before actually evaluating the expression. You can parse the expression with math.parse(...), and iterate over the returned expression tree to find all functions and variables used in the expression. See docs: https://mathjs.org/docs/expressions./expression_trees.html

@WesleyKapow
Copy link

Ah I see, yes those args are needed for sure.. /shrug unsure of a solution. As I said I'm not actually blocked on this as I just pushed my proxy scope down a level so the scope I actually pass around is {scope: proxyScope}, that way the Object.assigns leaves it in tact. Maybe the outcome here is a blurb in the readme/docs around rawArgs and what scope is defined as when it gets passed? It's also likely I'm very much an edge case so maybe complicating the docs isn't worth it. It just definitely caught me off guard. Future me will find this issue though :)

Re "lazy fetching": It's not async, it being "lazy" allows me to determine the dependencies at evaluation time and wire up their reactivity. I in fact started with what you describe in parsing and grabbing the references via the nodes. Things got more complicated however when I allowed for accessing dynamic symbols, e.g. foo[bar].baz. Now which baz you depend on depends on the value of bar. I could, every time I run the expression also do the dependency parsing, but that seemed painful. A proxy really simplified things.

@josdejong
Copy link
Owner

That makes sense using a proxy in your case, I understand.

I think for now it's enough to clarify the docs, I did so in commit 3153de2.

Will close this issue now.

josdejong added a commit that referenced this issue May 6, 2020
* Update devDependencies

* Fixed `eigs` not using `config.epsilon` (see #1789)

* Should be able to take NAMED_DELIMITER as object keys (#1798)

Co-authored-by: Jos de Jong <wjosdejong@gmail.com>

* Update history

* Clarify the documentation on `scope` when using `rawArgs`, see #1055

* Bump @babel/preset-env from 7.9.0 to 7.9.5 (#1810)

Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.9.0 to 7.9.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](babel/babel@v7.9.0...v7.9.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Prefix the cli test with 'node' so it works on windows (#1807)

* Prefix the cli test with 'node' so it works on windows

Shouldnt provide any issues for other systems I hope

* Revert "Prefix the cli test with 'node' so it works on windows"

This reverts commit 4cd2704.

* Revert "Revert "Prefix the cli test with 'node' so it works on windows""

This reverts commit 268b594.

Co-authored-by: Jos de Jong <wjosdejong@gmail.com>

* Fix #1808: `toNumber()` not working on a unitless unit (#1811)

* Update history

* Fix #1813: bug in engineering notation for numbers of function `format`, sometimes resulting in needless trailing zeros

* Improve explanation of engineering notation in function format

* Publish v6.6.3

* Bump uglify-js from 3.8.1 to 3.9.0 (#1816)

Bumps [uglify-js](https://github.com/mishoo/UglifyJS2) from 3.8.1 to 3.9.0.
- [Release notes](https://github.com/mishoo/UglifyJS2/releases)
- [Commits](mishoo/UglifyJS@v3.8.1...v3.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Publish v6.6.4

* Bump uglify-js from 3.9.0 to 3.9.1 (#1818)

Bumps [uglify-js](https://github.com/mishoo/UglifyJS2) from 3.9.0 to 3.9.1.
- [Release notes](https://github.com/mishoo/UglifyJS2/releases)
- [Commits](mishoo/UglifyJS@v3.9.0...v3.9.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Bump karma from 4.4.1 to 5.0.3 (#1830)

Bumps [karma](https://github.com/karma-runner/karma) from 4.4.1 to 5.0.3.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](karma-runner/karma@v4.4.1...v5.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Bump karma-mocha from 1.3.0 to 2.0.1 (#1832)

* Bump karma from 5.0.3 to 5.0.4 (#1839)

Bumps [karma](https://github.com/karma-runner/karma) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](karma-runner/karma@v5.0.3...v5.0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Bump mocha from 7.1.1 to 7.1.2 (#1827)

* Update devDependencies

* Fix #1834: value `Infinity` cannot be serialized and deserialized

* Fix broken bundle tests and linting issues

* Fix unit test on node 8 (yeah, I know)

* Fix #1842: value `Infinity` not turned into the latex symbol `\\infty`

* Publish v6.6.5

* Fix fixer.io example, the free plan doesn't support SSL

* Change node versions

Co-authored-by: jos <wjosdejong@gmail.com>
Co-authored-by: Veeloxfire <58116051+Veeloxfire@users.noreply.github.com>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants