ScatterHQ / machinist

A library for constructing finite state machines
Apache License 2.0
58 stars 12 forks source link

Receiving input constants directly is not supported #7

Closed itamarst closed 10 years ago

itamarst commented 10 years ago

Contrary to the example, rich inputs are required by the public API of the FSM. Personally I'd prefer not to have to create a whole bunch of trivialInput objects for cases where I really don't need rich inputs, but if that's not going to happen the example should be fixed.

cyli commented 10 years ago

+1 - I ran into trouble with this because the example suggests rich inputs are not needed.

exarkun commented 10 years ago

Thanks. I agree that this is a problem which needs to be addressed. So far I haven't come up with a plan that involves being able to get rid of IRichInput and the related APIs/support code. The only hint of an idea that has occurred to me so far is that maybe there could be either an input in self.inputs.iterconstants() or IRichInput.providedBy(...) check to determine whether an input is merely an input symbol or a rich input object of some sort.

The idea of adding this kind of type checking doesn't hold any strong appeal for me so I'd to think of (or have suggested :smile:) a better solution. Perhaps in the process of writing more documentation about how to use rich inputs and why they're a good thing some further ideas will come up.

cyli commented 10 years ago

Ah ok, I was in the process of writing those checks. Should I not?

While perhaps IRichInput is a worthwhile thing, it seems like it would be easier for someone starting out, learning the library, to just use symbols, so it'd be nice to support both even if one were preferred.

exarkun commented 10 years ago

I think it might be premature... or maybe not? Just because I implemented the feature doesn't make me an expert on it. :wink: I'm tempted to say that writing some documentation first makes more sense - on the other hand, adding the checks doesn't really commit machinist to anything (all mistakes can be fixed!). So if you'd like to pursue this, please feel free. :smile:

itamarst commented 10 years ago

How about receive() takes two arguments, a required input symbol and an optional rich object?

Separately, when writing docs (or code?) it might be nice to show (support?) the shorthand "just use the class of the rich input as the interface" case which covers the large number of users who won't want to write extra boilerplate.

cyli commented 10 years ago

@exarkun: Oh hm... I have half of a doc change in process, but it seemed really long and boilerplatey (and I didn't understand the point of IRichInput or the inputContext), so I got distracted by this so that the doc could be shorter. Hang on, will at least submit a work-in-progress PR.

@itamarst: I've no particular objection to having it take two arguments, but the symbol is already required to be the return value of the symbol method on the rich object. It'd be the same checks anyway, right? (because machinist would want to enforce that the symbol passed matches the symbol returned by the rich object?)

I'm somewhat confused as to what you mean in the latter paragraph by "the class of the rich input as the interface" - doesn't the rich input object passed to receive need to be an instance?

itamarst commented 10 years ago
  1. I am suggesting removing symbol() from rich input requirements.
  2. I am separately suggesting rich objects be registerable simply by their class, rather than having to create an interface for each one. This may encourage subclassing, so... maybe the thing to do is receive(symbol, richobjects=[...]) i.e. you can optionally pass in a list of rich objects.
cyli commented 10 years ago

@itamarst Oh, ok. I don't actually know what rich objects are for, exactly, so I don't know how to evaluate that, but that does explain the 2 parameters to receive. :) Thanks!

exarkun commented 10 years ago

Yea, this discussion reinforces my hunch that documenting what rich inputs are for is a good first step. :smile:

exarkun commented 10 years ago

The changes in the referenced pull request to make the documentation correct, though, do strongly suggest to me that requiring a rich input instead of just an input symbol, even in trivial cases, is annoying and should be fixed.

cyli commented 10 years ago

@exarkun Random questions based on my having no idea what rich inputs are:

If these don't make sense, apologies. Was just thinking of rich inputs as a box I need to ship stuff in. I understand in the USPS system why I need boxes for shipping things (so they don't break and they stack nicely), but I also prefer to buy things pre-boxed so I don't have to box them before sending them out.

Actually I'd prefer to have other people box AND ship things out for me. :)

Update: oh oops, you beat me by a minute. :) Well, let me know what I should do. The checks are almost done, but I'll go do something else for now.

exarkun commented 10 years ago

is there a 1-to-1 mapping between symbols and rich input?

Nope. You can have multiple rich inputs for a single input symbol. An example of this is a state machine running some kind of negotiation over a network. The negotiation can fail because of an error, fail because the peer rejects your request, fail because of a timeout, etc. The state machine input for all of these might just be a failure symbol. The rich input might be different for each in order to represent details about the failure (eg for logging, to let an output that generates a network message include correct parameters, etc).

if not, then maybe accepting both would work because the user doesn't always want to provide a rich input for all symbols?

This does seem plausible, maybe not in the way you meant :smile:. The application I have that uses machinist has both the many-rich-inputs-to-1-input-symbol case as well as cases where there really is no rich input (though it still uses them because the API requires it; iow, it has cases where it would be simpler if it were allowed to pass an input symbol instead).

cyli commented 10 years ago

Nope. You can have multiple rich inputs for a single input symbol. An example of this is a state machine running some kind of negotiation over a network. The negotiation can fail because of an error, fail because the peer rejects your request, fail because of a timeout, etc. The state machine input for all of these might just be a failure symbol. The rich input might be different for each in order to represent details about the failure (eg for logging, to let an output that generates a network message include correct parameters, etc).

Oh ok! That makes sense. Gives me a little more idea about what rich inputs are for anyway :)