Yeah, just to be super-clear: You can think of any operator in Bubble…
whether it is a mathematical operator (+, -, /, *)…
a boolean/comparison operator (“is”, <, >, “contains”, “is emtpy”, “is not empty”, “is not”)…
an “arrow” operator (“<-min->”, “<-max->”, “<-range->”)…
a “colon” operator (“:merged with”, “:formatted as”, “:item #”, “:items until”, “:first”, etc.)
… as a function that returns a value before proceeding with any further
operations.
These function/operators sometimes have 1 operand (argument), but never have more than 2 operands (arguments).
So, you could think of expressions as always being evaluated from left to right, one operator after another… and you’d be mostly right.
BUT THERE IS ONE IMPORTANT CAVEAT:
Bubble is a typed language… and the type of the expression is dictated by the data type of the left side operand. ADDITIONALLY, input fields in the editor also have a type (the ultimate value of the expression put there must resolve to that type).
An operator can only be evaluated once both operands are of the same type. This is what mostly leads to confusion about the expression builder.
The operator function only “collapses” to a new value once both operands reach the same data type. (And note that in the latest versions of Bubble, the handy “evaluates to… type” that appears on hover can be very helpful here.)
Let’s consider a contrived and convoluted example:
I want to know if the Current User’s First Name has less than 6 characters.
Let’s say that I just want to report the truth of that in a text element on the page (I often advise folks to do this as a debugging technique, right?)…
Well, I can construct in the “long text” field of the text element:
Current User's First Name...
This is an expression of type text. I could stop here. It will be displayed. (And if Current User’s First Name is “keith”, it will display “keith”.) No issue will be thrown.
But this won’t give me my answer, right? So I must continue constructing the expression. I go on to construct:
Current User's First Name :number of characters...
The expression above (considered strictly as an expression) is of type number. But oddly, this will also let me stop. (And if Current User’s First Name is “keith”, the value here will be 5.)
Why can I stop? Well, the text element does its best to convert an argument of non-text type to text. Knowing that the numeric value 5 can be represented as the text value “5”, no error is thrown. (And, in run mode, the character “5” will be displayed.)
But still, I do not have my answer. So I continue:
Current User's First Name :number of characters < ...
If I stop here, the color of the expression in the long text field will be red and an issue will be raised by the Issue Checker. Why?:
- I have just introduced an operator (<). And the expression is not complete.
The < operator is a boolean operator – it resolves to a boolean (what Bubble calls a “yes/no”) and will return yes
if true and no
if false.
The < operator is also type-dependent, its operation is different depending upon the type of the leftmost operand.
The leftmost operand (Current User's First Name :number of characters
) resolves to a number. So, the rightmost part of the expression (the second operand) must also evaluate to a number before the operator can be evaluated.
HERE’S WHERE WE CAN GET CRAZY…
Recall that we want to know if the number of characters in the Current User’s First Name is less than the number 6… THERE ARE MANY (actually an infinite number of ways) to get to the number 6.
We could do it the boring way:
Current User's First Name :number of characters < 6
In our text element, this will look like this (I typed the number 6, bur in this context the token “6” is not interpreted as a text token, it is interpreted as a numeric value… the literal, actual “number 6”):
SUCCESS! The expression is complete! But WHY?
Well:
some_number < some_other_number
… is a valid boolean expression
BUT, as I just said, there are an infinite number of ways to get to the number 6. Let’s think about a few of them (purely conceptually, not syntactically mind you):
- 3 + 3 is 6 (because math)
- “keith” :number of characters + 1 is 6 (because the string “keith” has 5 characters)
- The date “June 19th, 2019” :extract month is 6 (because June is month number 6 of the year)
BUT… Can we construct any of those expressions on the right hand side of the < operator?
Let’s find out. We shall try them in order:
First, let’s see if we can construct 3 + 3 on the right… I type a 3 and then hit the “more” button and get…
^^^^ WHAT. THE. EVER. LOVING. FUCK?
What is going on here? I want to type “3 + 3”, and now I can’t get the addition operator (+). I am presented with what seem like a random (and painfully short) list of options.
Well, here’s what’s going on:
When I typed the three in, the expression builder said (just as it did when I typed 6 in), “Hooray! You made a valid expression!” And now we are done.
The operation COLLAPSES (evaluates) to a boolean.
Now the expression holds either yes
or no
and is of boolean type.
And now, I can only do things that one can do with a boolean. Hence the truncated list.
Hmm.
Shall we try again? What about the second idea ("keith" :number of characters
)? Let’s give it a go:
You can’t see it in a static image, but – no matter how much I type and type – I cannot spell/type keith here… So:
WE CANNOT TYPE a literal when we are in expression builder mode.
So we cannot use string (text) literals here.
Can we type an expression that might equal “keith” and then add 1 to it? Well, we can start… Recall that Current User’s First Name in this case is probably “keith”. So let’s have a go at it:
I can get THIS far…
SHIT! Again, as soon as the right had side of the < reaches the same type as the left hand side of the <, we are done.
WE CANNOT ADD a number to “Current User’s First Name:number of characters” because the < expression has already collapsed to a boolean.
GET IT?
At this point, you are probably catching on.
But here’s what can trip you up. Let’s try the third bullet point option we considered above… What about the current date’s month number?
Well, as I write this, it is in fact “June 19, 2019”. June is the 6th month of the year. So maybe (at least today) we extract the current month number from the current date and get 6 that way… Let’s have a go at it:
^^^^ HOLY SHIT! WE ARE GETTING SOMEWHERE!
The expression has not yet collapsed. The left hand side is a number (“5” if current user’s name is “keith”) and the right hand side is a date! So, the function is incomplete.
Can we continue? Let’s find out:
OH WOW. The expression has still not collapsed. (This is only because the type of “extract from date” can vary.)
But let’s carry on:
Still in the game! Let’s hit “Close”…
^^^^ hmmm… 
Look at that. ^^^^ LOOK AGAIN.
We successfully made an expression that has operators on BOTH SIDES OF THE <.
BUT WHY did that work?
Well: because the left side is a number, and now the right side is a number, too.
But now we are done. The expression COLLAPSES to a boolean. I can no longer add numbers to the right hand side. LOOK:
^^^^ the expression is now boolean and we only have boolean options available.
The above is @laurence’s error. He got to thinking that, just because sometimes a < can have multiple operators on both sides of the operator, that this is ALWAYS the case . It’s not.
The expression always collapses to an evaluated state AS SOON AS POSSIBLE. It’s just that – in this carefully constructed case – it took multiple operators to get the left hand and right hand sides to be of the same type.
So, let’s review: Where are we now?
Well, we have a completed expression that is TRUE in the following case:
If the number of characters in the Current User’s First Name is less than the 1-based index of the current day’s month.
Of course, we could build on this… But I think you get the idea now.
The MAIN point is this: The Bubble expression builder guides us through this process. It continually cues us about what is going on. If we plow ahead like we are sure we know what we are doing – ignoring what it is telling us – we will probably make a stupid error. That’s all.