Does FMP 18 Evaluate() Handle More Complex Expressions?

Since I wrote the postfix code, I have found it to be very forgiving and yet solid. You’re free to like any implementation, of course, and, of course, using those implementations you have zero control over anything in them.

Runtime errors are OK if you have robust try-catch (local error handling), which FMP lacks.

If you check the bottom three cases, my logic handles cases where FMP gives the silly unhelpful “?”. A “?” is NOT error handling. That’s just lazy coding at FMI where as I’ve noted in other cases, FMI just dumps the problem in your lap to figure out.

The implementation I coded also handles the in-determinant case 0/0.

postfix

Finally, I’ve yet to find a case with supplemental parentheses where the result was not correct. See expression 1 in the screenshot. Of COURSE if you change the parentheses inside the expression, the result would be different.

I have clients using this logic from many apps including one from FMP.

My philosophy is similar to Alan Cooper (father of Visual Basic): don’t report an error, fix the problem in code if possible and still return the correct result (or, worst case, after trying, return a real error message to help the user).


After reading your posting, I just added an “option” to my method to report on unbalanced parens. During the stack push/pop, I just do a simple count++ or count–. If the parens count != 0 at the end (after the last stack pop), I report it with the parens nesting level where the problem happened, but only if the user passes “true” for the new strict argument. Most won’t care or use it, but it’s there now as an option.

Thanks,

4 Likes

Alan Cooper, nice! Yeah I read something he wrote a while back about errors and the impression I got was that he was advocating for making it impossible for users to cause errors. I can see how this would apply if you’re allowing users to type in expressions, and FWIW the calculator on Mac allows unresolved parentheses too, so you might be in good company ;).

I’d need to refresh my memory but I don’t remember him saying the same about developer error, and that distinction remains important to me, at least. I wanna know any and all pre-runtime issues with my code as I write it. And having confidence in the syntactical soundness of the code frees up brain cycles to focus on writing user-friendly apps.

As for FM, yeah ‘?’ By itself is no good, but I can’t fault them when evaluationerror() is available for this exact thing. They have error code 15 to report divide by zero errors too. As always, I’m sure they could improve this more. Continuous Improvement! :metal:

1 Like

No, if you haven’t read Alan Cooper’s “About Face”, I would start there. It’s a bit dated, but still good. He has another great book “The inmates are running the asylum”. You’ll change the way you think about software design with his insights. He has other free resources online.

I would also recommend Code Complete 2 review also about error handling (chapter 3) especially and chapter 8 (defensive programming). And a cover-to-cover read of Code Complete 2 if you haven’t read it.


Since FMP still doesn’t have even basic notepad-level refactoring–simple search and replace in all scripts and CFs–it’s hard for me (YMMV) to take it too seriously as a development product.

Furthermore, rather than globing on extra features in every release that few need (like the new very slow while statement), FMI should instead focus on making the product more usable.

1 Like

My bad, to get the error code 15, I needed to also wrap the EvaluationError with the actual Eval() nested inside as shown in the help.

I posted a sample file above that handles the error, and returns the actual error message.

https://my.filemakers.community/uploads/short-url/bQAk2veJMGApcOMirzzVpxOJs3S.fmp12

4 Likes

Thanks J. I was just trying to see what extra work was involved in FMP to do what I had already implemented. I see you added a fair amount of code to your example. Appreciate your posting. :slight_smile:

To add to @jormond’s example calc, if you want Evaluate() to run only once you can write the expression like below. $~eval.result can use any $ or $$ namespace you want… a UUID would be a good candidate to avoid possible collisions). This saves the result of Evaluate and EvaluationError at the same time.

Let ([
    // Your expression
    ~exp = "(1+1+1" ; 

    ~wrappedExp = "Let ( $~eval.result = " & ~exp & " ; \"\" )" ;
    ~err = EvaluationError ( Evaluate ( ~wrappedExp ) ) 
];
    If ( ~err = 0 ; $~eval.result ; ErrorCode ( ~err ) )
)

Easy

1 Like

Can make it a CF:

// EvalBetter(expression)
Let ([
    ~err = EvaluationError ( Evaluate ( "Let ( $EvalBetter.8EE912BF84EE41F29BD5DFC24E98BF29 = " & expression & " ; \"\" )"  ) ) 
];
    If ( ~err = 0 ; $EvalBetter.8EE912BF84EE41F29BD5DFC24E98BF29 ; ErrorCode ( ~err ) )
)
2 Likes

You have a dependency in that code. ErrorCode() is not a standard function.

1 Like

If you download jormond’s example you’ll find a copy of that specific function. Or you can add your own. Most developers I’ve worked with use some version of that CF that translates fm codes to error messages.

Thanks for pointing it out for anyone who might not have downloaded the file I referenced. Hopefully that prevents some confusion. :+1:

2 Likes

In About Face: Chapter 8: Defensive Programming

p. 206: Fail hard during development so that you can fail softer during production

This is precisely what I meant when I said that developers should experience the headache of dealing with a strict language/editor. (I.e. not forgiving or "robust" as you called it). Cooper goes on to say that errors should be "painful" during development to encourage developers to fix them. He says they should terminate the program, actually (brutally strict).

p. 204

Check data crossing the boundaries of a safe area for validity, and respond sensibly if the data isn’t valid.

This is a really awesome concept as it relates to both user input and the code itself. Not novel but still awesome. He advocates for a barricade between the dirty data area and the safe area, and a "barricade" in between that sanitizes data. This applies to all sorts of stuff like validating email/phone format or required fields. As it relates to parens, I've seen a really cool feature in online calculators that infer closing parens (like google's calc). They will show a grayed out closing parenthesis at the end so the user doesn't have to guess the inference or remember the rule baked into the custom parsing code. And to drive the "barricade" idea home, Google's calculator seems to add the missing parenthesis before evaluating the expression, so it's not actually letting the imbalanced expression through the gate as-is.

Anyway, thanks for the recs, I look forward to reading more of "About Face", it's really good so far!

1 Like

Thank You for the hint to that book! Bought a copy for ‘kindle’ right now

@jormond’s UIs are really nice. I loved his calculator dark display with the light text.

1 Like

I also recommend “Debugging the Development Process”. Lots of good insights there.

Thanks for your note.

IMHO, the biggest dependency is FMP itself. All these code examples will only work with FileMaker. A micro-service implementation, OTOH, would work with any HTTP caller and could be written in the language of choice.

1 Like

While I understand your point about portability, I have less aversion to dependencies. I take issue with the premise that dependencies are bad. The entire web world is embracing dependencies as a means of increasing their productivity. And if your concern is being able to access your FM functions via HTTP, you CAN, just use the data api! Pass it a param like you would anything else.

There’s a concept I’m fond of called “code for the hot path”. It says that your code should be optimized for the road most traveled. I’ve heard you make the case that Java can generate UUIDs faster than FM. Well not if you just need one UUID inside FM itself and you have to reach across the network to get a UUID from your custom Java dependency. And if your counterpoint is that you can run Java locally, that’s just another dependency to install on every client machine. So, if an FM client is the biggest consumer of your functionality/services, then it actually makes a lot of sense to bake the functions right into the fm solution.

In summary, I agree that if you’re running many different clients that share the same functionality, as it sounds like you often do, then yeah separate the functionality from the DB, otherwise FM does a fine job and can serve that same functionality just fine. I don’t disagree that other languages are faster, but the rise of AWS, slow but simple languages like Python, and even the microservices model itself, shows that it is development speed that is usually more important.

But yeah, if all FM is being used for is the Evaluate function, then that’s a big, expensive dependency and a pretty silly investment!

3 Likes

This very much brings up what I learned in my first semester at university. The ‘?’ simply and purely leaves it with the developer to catch it and put out a meaningful message to the user.
Sometimes this is justified, but many times not, when standard cases of calculus rules apply.

I didn’t mean to imply that dependencies are bad. My web services have lots of dependencies, for example – but they’re all internal. And, none of those dependencies are on FMP or FMS, or on any other application program or on any operating system, etc.

I enjoy the forum and seeing what kinds of things people are doing. I’ve posted almost 100 FMP examples that use services (my FMP micro-service project where I’ve created code to help answer forum user questions has about 150 methods).

I personally dislike proprietary software. Should FMI go out of business, anything I’ve written will keep humming along. Visual FoxPro went “toes up” also, as you recall, and nobody thought that would happen either. Until it did.

In any case, I’ve picked up lots of super useful ideas on the forum – things like mind mapping which I’d never done before. Now I can’t stop creating mind-maps. Help! :slight_smile:

Thanks for your note.

3 Likes

As a typical FM developer (field expert, no explicit coder training) I do not use Evaluate () unless it is absolutely necessary. I dare say that this function is not much used by the average developer, though extremely helpful if really required. Not to use in loops over huge sets of records.

1 Like

Excellent thread. Thanks for initiating it, @anon45965781.
This is a thread that gives food for thought and consideration.
So thank you @jormond, @jwilling and all who shared thoughts and expertise.

1 Like