Git Product home page Git Product logo

Comments (11)

mweststrate avatar mweststrate commented on May 22, 2024

Hi,

I'm not sure whether it fits your current approach, but I think I would
express it a bit along the following lines:

class Point {
    constructor(x, y) {
           extendReactive(this, {
                  x: x,
                  customY: y,
                  useDoubler: false,
                  y: function() {
                        return this.useDoubler ? this.x * 2 : this.customY
                  }
          })
     }
}

Does that make sense in your use case?

On Wed, Sep 23, 2015 at 8:32 AM, KS Sreeram [email protected]
wrote:

Let’s say I have a class Point defined like this:

class Point {
constructor(x, y){
extendReactive(this, {
x: x,
y: y
});
}
}

Point has two independent observable properties x and y.

For a specific instance of Point I would like to constrain y so that it
is always twice x. I’m currently doing it this way:

var p = new Point(10, 20);
sideEffiect(() => {
var newY = p.x * 2;
setTimeout(() => {p.y = newY;}, 0);
});

I’m using setTimeout because I can’t update the state inside a
reactive-view. But it’s pretty clunky. Is there a better way to do this? I
know I can use plain JS objects instead of custom classes, but in my actual
scenario I need to use custom classes because they are more complex and
have methods on them.

Thanks in advance!


Reply to this email directly or view it on GitHub
#31.

from mobx.

kssreeram avatar kssreeram commented on May 22, 2024

It doesn't work from a separation of concerns point of view. The problem is that Point has no knowledge of the constraint. It's the use-site of Point that knows about the constraint. Also, different use-sites impose different constraints.

from mobx.

mweststrate avatar mweststrate commented on May 22, 2024

That sounds like a complicated case / model? Maybe use separate subclasses
per constraint? Or if there are many variations, inject the constraint in
the Point class and make all attributes of the Point just view functions
that use the constraint?

Note by the way that current error in the console is at the moment merely a
warning, the code doesn't really throw so at the moment your solution
should work even without the timeout.

I'm still searching what the best strategy is here, I feel that
conceptually views should remain pure so that you can reason about them
more easily, but on the other hand, maybe there are indeed valid use-cases
for not having pure views. So, could you elaborate a bit more on your use
case?

On Wed, Sep 23, 2015 at 9:13 AM, KS Sreeram [email protected]
wrote:

It doesn't work from a separation of concerns point of view. The problem
is that Point has no knowledge of the constraint. It's the use-site of
Point that knows about the constraint. Also, different use-sites impose
different constraints.


Reply to this email directly or view it on GitHub
#31 (comment)
.

from mobx.

kssreeram avatar kssreeram commented on May 22, 2024

There are multiple scenarios where I’m facing this problem. Here is one scenario:

I have a InputField component that has two state variables: value which is a string, and errorMode a boolean flag. value is displayed on-screen and is editable. When errorMode is true, the component is displayed with a light-red background to indicate an error.

As far as the InputField component is concerned, the two properties are independent. The InputField component is only concerned with display and styling.

If I use this component for entering an email address, I’ll need the following constraint:

errorMode = !isValidEmail(value)

If I use this component for entering a number, then I’ll need this:

errorMode = !isValidNumber(value)

Another case is a sign-up form which contains an InputField for email. errorMode can be set if the field contains an invalid email address or if the server has informed us that the email address is already in use. The constraint here is a bit more complex.

Btw, thanks for letting me know the MObservable error is just a warning. I’m planning to disable the warning in my local copy. Do you think this change could cause other problems with MObservable?

Thanks for the help.

from mobx.

mweststrate avatar mweststrate commented on May 22, 2024

There are no technical limitations at the moment that require the warning,
it's merely a conceptual thing. So it is still up for discussion whether it
should be allowed from a functional point of view, not from a technical
point of view. In issue #30 we had the same kind of discussion, and it that
case it fitted nicely in pure views in the end. But if people keep running
into this limitation, maybe I make it a configurable flag. Note that the
principles behind it are explained here:
http://mweststrate.github.io/mobservable/intro/concepts.html

Your errorMode example I would roughly solve as follow:

var errorState = makeReactive({
    value: null,
    validator: null,
    errorMode: function() {
        if (!this.validator)
             return false;
        else
             return !this.validator(this.value);
    }
}

And then simply:

errorState.validator = isValidNumber;
errorState.value = "hi"

If async communication gets into play, you could also use observe
(previously called side effects) functions and merge the different inputs
in errorMode:

var errorState = makeReactive({
    value: null,
    validator: null,
    errorMode: function() {
        return this.validationError || this.emailIsInUse
    },
    validationError: function() {
        if (!this.validator)
             return false;
        else
             return !this.validator(this.value);
    },
    emailIsInUse: false
}


observe(function() {
   server.validateEmail(errorState.value, function(isInUse) {
         // triggered async, so it is allowed to update state again.
         errorState.emailIsInUse = isInUse;
   });
});

Btw, there is now also an observeAsync method that basically exposes your
original timeout pattern, see the last comment in issue #28

from mobx.

dschalk avatar dschalk commented on May 22, 2024

Maybe you could make pure views the default and have a simple opt out option, something like "use strict" in Javascript. Development team leaders everywhere could enforce best practices by requiring a special dispensation, or maybe a majority team vote, if someone had a special need to use the opt-out directive. I love the chapter from the Tao Te Ching which, loosely translated, says that a bad emperor is feared by the people; a better emperor is loved and admired by the people; but the best emperor is unknown to the people. When the goal is accomplished, the people say, "We did this ourselves." Meetings are generally a waste of time, but a few meetings to devise strategies for making code maintainable, in which a true consensus is reached, could result in a team which says, "We thought of this ourselves", largely oblivious to the leader's deft, unobtrusive manipulation of the process.

For your published library, my preference would be to provide the means in the API to manipulate state during the computation of a reactive view. I stopped using the Yesod Haskell web application framework because it was so 'opinionated'. Everyone is entitled to an opinion, but Michael Snoyman apparently can't bear to know that people are writing sloppy, buggy code with his library, so he imposes his opinions on library users by declining to expose functionality they might want. He explains this well, http://www.yesodweb.com/, and his opinions are first-rate and deserving of the utmost respect, but In order to get things done in 'off the beaten path' use cases, I sometimes needed to alter his library code. I would have preferred to have been given more options in the API.

The Glasgow Haskell Compiler tolerates Haskell coders' use of functions that compiler authors rely on to communicate directly with machines and with the C language. These are not Haskell pure functions, and could easily result in buggy, hard-to-maintain code. The two most-often-used functions in this category are 'unsafeCoerce' and 'unsafePerformIO' and its variations. I generate random numbers for the dice roll in the 'Game of Score' app. No referential transparency there. It uses the notorious 'unsafePerformIO hack'. I don't worry about it because I don't extract the numbers from the IO Monad which contains the numbers until I get to the final function 'main' and broadcast them to 'Score' game players. In one of the first versions, I used 'unsafePerformIO' to extract the numbers right in the middle of the program. The numbers were never used by the program and the compiler never saw them again after they were generated, so all I had to worry about was someone reading the code on Github and forming a low opinion of my coding ability. The point I want to make here is that Haskell programmers and people reviewing their code are reminded of the riskiness of using these functions by their names. Maybe your directive for overriding best practices could be "use questionable coding practices' or 'use dangerous'.

I cleaned up part of my'mobservable-monads' repo last night and added some commentary in the 'Working With Numbers" section. I know you are extremely busy, and I don't want to impose upon your time, but here's a suggestion: I think you would enjoy the "Working With Numbers" section of "mobservable-monads, and possibly find the Haskell monad concept of pulling a value out of one monad and mapping it to an instance of possibly even another type of monad monad either (1) thought provoking, (2) essentially what you are already doing, (3) boring, (4) something else. Commentary for the whole "Working With Numbers" section is only 12 or so sentences. I reproduced the section in README.md at https://github.com/dschalk/mobservable-monads, so you can see what I am talking about at that repo.

And here is a heartfelt recommendation : Even if you are certain that you will never have any use for Haskell, I think you will find (if you haven't already done so) Part II of Simon Marlow's "Parallel and Concurrent Programming in Haskell" to be almost spine-tingling in the poetry of its clear exposition of some of the most simple yet powerful code you will ever see. This is elegance par excellence. The concurrency section, Part II, starts on Chapter 7, "Basic Concurrency: Threads and MVars". In my "Game of Score" project, I use a modified MVar called a 'TMVar, which is explained in Chapter 10, "Software Transactional Memory". It facilitates atomic updates.

The TMVar in "Game of Score" is named ServerState. It contains the current list of connected players, the groups they are in, and their current scores. My app has immutable state, according to the Haskell concept of 'immutable', but players, their groups, and their scores constantly change when players compete; and current state is always available upon request from the ServerState TMVar. The trick is that state is stored in the immutable TMVar. Updates involve removing the state, making a new state that differs from the removed one in the desired way(s), and inserting the new state in the empty TMVar. In a Javascript application, mutating the encapsulated state without removing it would likely be the way to go. I'm still mulling this over and sleeping on it, but it occurs to me that mobservable might benefit from doing something similar; something which would allow more developer flexibility regarding dynamic aspects of state without using view functions to mutate state (in the haskell sense of mutating) during computations. In a Node.js websockets application, such a thing might even be useful in the server for managing state, much as Haskell TMVars handle state in my game app.

I think it is best to err on the side of giving developers too many options in the API, rather than too few. Warnings and flags with alarming names are good, but in the end, give them an API with functionality that allows them to do whatever wild and crazy (but possibly beneficially innovative) things they want.

from mobx.

dschalk avatar dschalk commented on May 22, 2024

I made the mobservable-monad's README.md more legible.

from mobx.

mweststrate avatar mweststrate commented on May 22, 2024

The next version introduces a mobservable.strict setting, which, if set to true (the default) throws if a view changes a state value, but accepts it if set false. This way users can apply mobservable in the style that suits there needs and we can investigate later on how both options work out in general.

from mobx.

dschalk avatar dschalk commented on May 22, 2024

Perfect! The low-keyed name feels better than 'unsafeCoerce'.

Maybe with mobservable.strict = false and logLevel = 2, you could still send warnings to the console.

from mobx.

mweststrate avatar mweststrate commented on May 22, 2024

Good point! I'll add that.

from mobx.

mweststrate avatar mweststrate commented on May 22, 2024

Mobservable 0.7 has been released, including the aforementioned strict option.

from mobx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.