Everything is An Expression
There is nothing revolutionary about this per se. The expression-oriented approach is a functional programming technique.
Expression-oriented code is simpler and less cluttered than statement-oriented code, because of fewer assignments and no explicit return
statements. The lack of distinction between expressions and commands enables conceptual uniformity (see Referential transparency) and bottom-up structure.
Some modern languages have adopted functional programming concepts (e.g. C#, Python, Ruby).
Some scholarly insight on the benefits of functional practices:
- Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs - John Backus
Interesting articles:
- Why Functional Programming is Important in a Mixed Environment
- Is C# becoming a functional language?
As to the comment about performance concerns, the possible overhead related to choice of paradigm is probably negligible. Even in C, most statements evaluate as an expression - however, a comparison between a compiled language (C) and an interpreted language (CoffeeScript) is rather useless.
On a theoretical note, an imperative language represents the control flow in more of a machine-oriented way, which may allow for easier hand-optimization than a functional language.
Language performance and its significance depend heavily on the use case. Concerning JavaScript and whatever code transformation on top of it, this performance discussion is completely irrelevant. The gains in productivity outweigh any slight performance hit.
What is the difference between an expression and a statement in Python?
Expressions only contain identifiers, literals and operators, where operators include arithmetic and boolean operators, the function call operator ()
the subscription operator []
and similar, and can be reduced to some kind of "value", which can be any Python object. Examples:
3 + 5
map(lambda x: x*x, range(10))
[a.x for a in some_iterable]
yield 7
Statements (see 1, 2), on the other hand, are everything that can make up a line (or several lines) of Python code. Note that expressions are statements as well. Examples:
# all the above expressions
print 42
if x: do_y()
return
a = 7
Expression Versus Statement
Expression: Something which evaluates to a value. Example: 1+2/x
Statement: A line of code which does something. Example: GOTO 100
In the earliest general-purpose programming languages, like FORTRAN, the distinction was crystal-clear. In FORTRAN, a statement was one unit of execution, a thing that you did. The only reason it wasn't called a "line" was because sometimes it spanned multiple lines. An expression on its own couldn't do anything... you had to assign it to a variable.
1 + 2 / X
is an error in FORTRAN, because it doesn't do anything. You had to do something with that expression:
X = 1 + 2 / X
FORTRAN didn't have a grammar as we know it today—that idea was invented, along with Backus-Naur Form (BNF), as part of the definition of Algol-60. At that point the semantic distinction ("have a value" versus "do something") was enshrined in syntax: one kind of phrase was an expression, and another was a statement, and the parser could tell them apart.
Designers of later languages blurred the distinction: they allowed syntactic expressions to do things, and they allowed syntactic statements that had values.
The earliest popular language example that still survives is C. The designers of C realized that no harm was done if you were allowed to evaluate an expression and throw away the result. In C, every syntactic expression can be a made into a statement just by tacking a semicolon along the end:
1 + 2 / x;
is a totally legit statement even though absolutely nothing will happen. Similarly, in C, an expression can have side-effects—it can change something.
1 + 2 / callfunc(12);
because callfunc
might just do something useful.
Once you allow any expression to be a statement, you might as well allow the assignment operator (=) inside expressions. That's why C lets you do things like
callfunc(x = 2);
This evaluates the expression x = 2 (assigning the value of 2 to x) and then passes that (the 2) to the function callfunc
.
This blurring of expressions and statements occurs in all the C-derivatives (C, C++, C#, and Java), which still have some statements (like while
) but which allow almost any expression to be used as a statement (in C# only assignment, call, increment, and decrement expressions may be used as statements; see Scott Wisniewski's answer).
Having two "syntactic categories" (which is the technical name for the sort of thing statements and expressions are) can lead to duplication of effort. For example, C has two forms of conditional, the statement form
if (E) S1; else S2;
and the expression form
E ? E1 : E2
And sometimes people want duplication that isn't there: in standard C, for example, only a statement can declare a new local variable—but this ability is useful enough that the
GNU C compiler provides a GNU extension that enables an expression to declare a local variable as well.
Designers of other languages didn't like this kind of duplication, and they saw early on that if expressions can have side effects as well as values, then the syntactic distinction between statements and expressions is not all that useful—so they got rid of it. Haskell, Icon, Lisp, and ML are all languages that don't have syntactic statements—they only have expressions. Even the class structured looping and conditional forms are considered expressions, and they have values—but not very interesting ones.
So is everything an expression in F#?
As already said, every syntactical construct in F# is an expression. F# does not distinguish between statements and expressions (and so I'd say that the WikiPedia quote posted by Robert is a bit misleading - F# does not have statements).
Actually, the above is not fully true, because some constructs in F# computation expressions such as let!
are not expressions, but we can ignore that.
What does that mean? In C#, the syntax of for
and method calls is defined something like this:
statement := foreach(var v in <expression>) <statement>
| { <statement> ... <statement> }
| <expression>;
| (...)
expression := <expression>.<ident>(<expression>, ..., <expression>)
| <literal>
| <expression> + <expression>
| (...)
This is very simplified, but it should give you the idea - a statement is something that does not evaluate to a value. It can be foreach
loop (other loops), a statement block (with multiple statements) or an expression with semicolon (where the result of the expression is void
or is ignored). An expression is, for example, method call, primitive literal (string, int) or a binary operator.
This means that you cannot write certain things in C# - for example, the argument of method call cannot be a statement (because statements do not evaluate to a value!)
On the other hand, in F#, everything is an expression. This means there is just a single syntactic category:
expression := for v in <expression> do <expression>
| <expression>; <expression>
| <expression>.<ident>(<expression>, ..., <expression>)
| <literal>
| <expression> + <expression>
| (...)
This means that in F# all syntactic constructs are expressions, including for
and other loops. The body of for
is also an expression, but it would not make sense if the expression evaluated to some value (i.e. 42
), so the types require that the result of the body is unit
(which does not carry any information). Similarly, the first expression in sequencing (<expr>; <expr>
) should return unit
- the result of sequencing is the result of the second expression.
This makes the language simpler and more uniform, but you can write some odd things:
let x = (for i in 0 .. 10 do printfn "%d" i); 42
This will print numbers from 0
to 10
and then define a value x
to be 42
. The assignment is a sequencing of expressions (<expr>; <expr>
) where the first one is for
loop (that has a type unit
, because it does not evaluate to anything) and the second one is 42
, which evaluates to 42.
is any JavaScript statement an expression?
I'd say no, as you can't use just any statement where an expression is expected:
// SyntaxError: Unexpected token var
var a = var b;
// SyntaxError: Unexpected token if
var c = if (true) {};
The undefined
shown in Chrome's console is due to its use of eval()
(or a native/internal equivalent), which evaluates any code:
var a = eval('var b;');
console.log(a); // undefined
The undefined
isn't the result of var b;
, but because eval()
itself still has a return value -- whether the evaluated code supplied it or not.
Statements vs Expressions in Haskell, Ocaml, Javascript
This is a bit of a complicated topic. Technically, in ML-style languages, everything is an expression. However, there is some syntactic sugar to make it read more like statements. For example, the sample you gave in F# would be:
let a = 1
let b = 2
let c = a + b
printfn "%d" c
However, the compiler silently turns those "statements" into the following expression for you:
let a = 1 in
let b = 2 in
let c = a + b in
printfn "%d" c
Now, the last line here is going to do IO, and unlike in Haskell, it won't change the type of the expression to IO
. The type of the expression here is unit
. unit
is the F# way of expressing "this function doesn't really have result" in the type system. Of course, if the function doesn't have a result, in a purely functional language it would be pointless to call it. The only reason to call it would be for some side-effect, and since Haskell doesn't allow side-effects, they use the IO
monad to encode the fact the function has an IO producing side-effect into the type system.
F# and other ML-based languages do allow side-effects like IO, so they have the unit
type to represent functions that only do side-effects, like printing. When designing your application, you will generally want to avoid having unit
-returning functions except for things like logging or printing. If you feel so inclined, you can even use F#'s moand-ish feature, Computation Expressions, to encapsulate your side-effects for you.
Related Topics
How to Read a Httponly Cookie Using JavaScript
What Is Wkerrordomain Error 4 from Wkwebview
How Can D3.Transform Be Used in D3 V4
Splitting a Js Array into N Arrays
Check If One Date Is Between Two Dates
What Is Right Way to Do API Call in React Js
Simplest Way to Wait Some Asynchronous Tasks Complete, in JavaScript
Download Image with JavaScript
Use Browser Search (Ctrl+F) Through a Button in Website
How to Pass Parameters in Get Requests with Jquery
How to Write Asynchronous Functions for Node.Js
Get Word Under Tap from Uiwebview Using JavaScript
Push Is Overwriting Previous Data in Array
How to Export Tables to Excel from a Webpage
Angular 4.3.3 Httpclient:How Get Value from the Header of a Response
Google Maps Places API V3 Autocomplete - Select First Option on Enter