14

Unlike most programming languages, every value in Mathematica is an expression. Applying any operation to any expressions always yields another expression. Consequently, Mathematica effectively has only one type. Mathematica does no static type checking and, arguably, doesn't even check types dynamically (at run-time).

For example, adding the integer expression 1 to the string expression "foo" in Mathematica results in the (nonsensical) expression 1 + "foo" but no error. In other cases, Mathematica provides feedback about nonsensical input but the checks that generate this feedback must be performed explicitly by the programmer.

Thus, is it fair to describe Mathematica as an untyped language as opposed to a statically or dynamically typed language?

J D
  • 48,105
  • 13
  • 171
  • 274
  • 1
    @Yaroslav Bulatov: The post you cite was about Mathematica's performance. This Stack Overflow question has nothing whatsoever to do with Mathematica's performance. This is about classifying Mathematica's type system. – J D Dec 30 '10 at 01:50
  • 3
    the question seems subjective – Yaroslav Bulatov Dec 30 '10 at 02:35
  • You are not really asking whether a CAS based upon symbolic term rewriting is a typed language, are you? Why is `1 + “foo”` nonsensical in say Klingon algebra? BTW expressions are not always evaluated and thus _nonsensical_ in Mathematica simply means the less strong “there is no rule for that”. – gwr Feb 05 '22 at 14:19
  • I consider (loosely speaking) Mathematica as a very strongly typed language: Everything really is a String. :) – gwr Feb 05 '22 at 14:27

5 Answers5

18

Instead of "type", what Mathematica has is the concept of a "head", where any Mathematica expression possesses one. This is in line with their "everything is an expression" paradigm.

One can peer at the structure of a Mathematica expression through the functions FullForm[] and Head[]. For instance, Head[3]returns Integer,Head[2/3] returns Rational, Head[I] returns Complex, Head[.3] returns Real, Head[a] returns Symbol (assuming you had not yet assigned anything to a), Head["a"] returns String, Head[{2}] returns List... i'm sure you get the idea already.

The beauty of this is that one can write functions such that they can only accept arguments with specific heads. For instance:

f[x_Real] := x^2

f[3]
f[3]

f[3.]
9.

This discussion on patterns should give you ideas on how to set up functions such that they work only on objects with specific heads or sets of heads.

  • And how do you see that relating to the classification of Mathematica as statically, dynamically or un-typed? – J D Dec 30 '10 at 23:02
  • 3
    @OP and downvoter: There are no "types", just "heads". I am personally not seeing why it matters so much to you to classify it as "typed", "untyped", or somesuch nonsense. –  Dec 31 '10 at 00:26
  • To use `Plus[]` as an example, the thing with routines/functions/procedures in *Mathematica* is that they look at the head of (or more generally, the patterns matched by) its inputs, and act accordingly. `1+1/2` gives a result `3/2` with `Rational` head because `Plus[]` knows what to do when given a `Rational` and an `Integer` input. In contrast `1+Sqrt[2]` does not give a "useful" result because `Plus[]` does not know how to deal with an input with the head `Sqrt[]`. –  Dec 31 '10 at 07:01
  • 3
    @belisarius: I downvoted this answer because it is tenuously related to my question about the classification of Mathematica's type system. Other people must have downvoted the other answers. – J D Jan 01 '11 at 19:49
7

If we consider the phrases "statically typed" and "dynamically typed" as jargon referring to when a language checks the validity of operations against types, then I think it is fair to characterize Mathematica using the jargon "untyped" -- in the sense that it "never" checks whether an operation is valid for a type.

I do like Belisarius' use of the term "type-agnostic", however. I say this because while almost all type-checking in the language is idiomatic (i.e. implemented by the programmer, not the language), so is the concept of applying an operator to typed operands!

Consider the "nonsensical" example of 1 + "foo". I think it is fair to say that a significant fraction (approaching unity) of all Mathematica users trips over cases such as this as they are first learning the language. The problem is particularly evident when one is writing code in, say, the style of C. There is much discussion in Mathematica circles as to how to handle situations such as these.

On the other hand, this weakness is also Mathematica's greatest strength. Mathematica is optimized for creating new notations. Many, many notations have the concept of + that behaves very similarly to addition in elementary arithmetic. When building such a notation, it would very inconvenient if Mathematica stepped in and complained that the operands to + were not numbers. In such a higher-level application of Mathematica, the "nonsensical" example is not only "sensical", but actually crucial.

So, with that in mind, the question of type is frequently moot. Hence, I like Belisarius' "type-agnostic" characterization. Upvote him, I did ;)

Edit

I'll try to clarify what I had in mind when distinguishing between "untyped" and "type-agnostic".

Reading over the various answers and comments, I tried to figure out what the difference was between Mathematica and LISP. The latter is generally held up as an example of "dynamically typed", although the core LISP evaluator is very much like Mathematica with hardly any type-checking. The type errors we see in LISP programs are mostly issued by hard-coded checks in (typically built-in) functions. +, for example, will only accept numeric arguments even though the evaluator itself could not care less one way or the other. Having said that, the "feel" of programming in LISP differs greatly from the "feel" of Mathematica (for me, at least). The 1 + "foo" example really captures that difference.

While I broadly agree with "untyped" as the characterization of Mathematica, I still felt that something was missing. Assembler seems untyped to me, as does early FORTRAN and pre-ANSI C. In those cases, the bit pattern of arguments was all that mattered, and the programs would continue on blithely if I passed a string argument where an integer was needed. Mathematica certainly shares this untyped behaviour. But there is a difference: in assembler and FORTRAN and C, it is extremely rare for this lack of type-checking to result in a good outcome. As I mentioned above, in Mathematica it is possible and sometimes even common to rely upon this kind of behaviour.

Enter "type-agnostic". I liked its non-committal stance, sounding less drastic than "untyped". I felt it reflected the essentially untyped nature of Mathematica, but left some wiggle room for those language features that readily support idiomatic type-checking in the LISP, dynamic style (i.e. the "head" idiom and supporting functionality).

So, in short, I feel that Mathematica hovers between being completely untyped and being dynamically-typed. "Type-agnostic" captured that sentiment for me. YMMV :)

I readily confess that no-one is likely to reconstruct anything I've written in this response simply from inspecting the phrases "untyped" and "type-agnostic". Again I emphasize that I think that "untyped" is a fair characterization of Mathematica, but I also like the fact that "type-agnostic" begs a lot of the questions being addressed by the various responses to this SO question.

Community
  • 1
  • 1
WReach
  • 18,098
  • 3
  • 49
  • 93
  • If someone else vote my answer, you have a place as campaign manager for my senatorial run :D – Dr. belisarius Dec 30 '10 at 01:00
  • +1 although I still don't understand what exactly is meant by "type agnostic". Is assembler type agnostic, for example? – J D Jan 01 '11 at 19:52
  • I can't quite follow the reasoning as to why say `+` does not generate an error when used as `1 + "foo"`. If the user wanted this to be valid when originally it generated an error, all he has to do is overload `+`. IMO, `+` not generating an error in this case is simply because something like `1 + f[x]` should be allowed as a symbolic expression, and `1 + String[]` looks very much like that. Unfortunately, the concept of symbolic variables/functions (that don't evaluate to anything) is not first-class in mathematica. – masterxilo Aug 29 '16 at 16:14
5

Mathematica does have some types, and it is dynamic. You have the types String, Integer, Real, Complex, List and Symbol. You can create functions operating on only one type by doing something like

f[x_Integer]:=x+1

to create a function which only operates on integers.

Mathematica is heavily based on patterns and substitutions; the types always seem to me to be another way to help you develop patterns. In the case of 1 + "foo", there is no pattern to evaluate a number added to a string, so the result is just the expression itself. In the case of 1 + 2, there is a pattern to add the numbers and it is evaluated. Mathematica's patterns and substitution rules can be much more complex, and it's best to read a book if you're interested.

El Developer
  • 3,345
  • 1
  • 21
  • 40
arsenm
  • 2,903
  • 1
  • 23
  • 23
  • 7
    Using `Integer` etc. as types is just a convention: The pattern `x_Integer` matches whenever the head of `x` is `Integer`. So `With[{x=Integer["hello"]},f[x]` would give `Integer["hello"]+1`... – Janus Dec 30 '10 at 01:23
  • @Janus: That obviously has some similarity with the run-time type tags used in the implementations of dynamic languages but the difference is that the "function" `f` is not really a function, it is a rewrite rule. – J D Dec 30 '10 at 01:56
  • 1
    @Jon Harrop. Exactly. I merely tried to make the point that what might appear to be a type system is just a rough approximation of a type system -- with absolutely no contracts. – Janus Dec 30 '10 at 04:04
  • @Janus: Yes, if those run-time type tags aren't being tested automatically then it isn't really dynamic typing and it certainly isn't static typing... – J D Dec 30 '10 at 22:51
  • 1
    Note that the "function which only operates on integers" is really run-time dispatch: if the head of `x` is `Integer` then this rule is applied otherwise another is looked for. If this were dynamically typed then the language would require that other arguments result in a run-time type error but Mathematica does not do this. – J D Jan 02 '11 at 22:02
  • Version 12 added [`Typed`](https://reference.wolfram.com/language/ref/Typed.html). – Alan Jun 11 '21 at 18:58
5

More from the practical, than the theoretical side of things, I believe you may say that Mathematica is more type-agnostic than untyped.

Moreover, you can construct easily a typed sub-language using things like (very basic example follows):

Unprotect[Set]; 

Set[a, x_] := If[Element[x, Integers], x, 0, 0];  

and then try:

a = 1; (*runs ok*) 

and

a = "caca"  (*assigns zero to a*)

Edit

Moreover, you may construct user-defined types as named patterns, and use them in the redefinition of Set above, instead of integers.
Type composition should work in the same way.

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
  • 1
    Can you elaborate on the difference between untyped and "type agnostic"? – J D Dec 30 '10 at 01:53
  • +1 because I like "type agnostic," but if you want to keep religion out of what could easily descend into a holy war, you could call it "optionally typed." You can assume any model that works for your problem as long as you don't expect it to be absolutely unbreakable. For example, static: 'f[a_List]'; dynamic: 'Head[a]'; untyped: 'g[a_]'. In reality MMA is neither fish nor fowl, and that's probably down to its genesis as a computational system (vs a general purpose language.) You might also ask, "Is it a functional language? If not, then what?" and receive lots more contradictory replies. – Tim Jan 03 '11 at 18:42
  • @Tim I dislike holy wars, so I decided to let the answer as it was originally posted and refrain myself to comment further. I think your comment is aligned with my thoughts, and perhaps much more clear than my answer. – Dr. belisarius Jan 07 '11 at 22:54
4

The short answer: Untyped or typeless. This is how Wolfram Research describes the product themselves. See here.

Long answer: Jon, I think your question really hinges on what you mean by untyped. To appeal to the definitive resource that is Wikipedia "In contrast, an untyped language, such as most assembly languages, allows any operation to be performed on any data, which are generally considered to be sequences of bits of various lengths."

Reading the earlier answers, it seems the heart of the debate is what should a type checker when it encounters an error. The usual answer is to STOP evaluation and report some kind of error. From several earlier questions (1) and (2) on Stackoverflow, we can see that there isn't a graceful way of doing this built-in to Mathematica. (I would add the caveat that with more emphasis on compilation to C in version 8 that it is possible to write type checked code but I am unsure whether this should be counted as part of the main language.)

Community
  • 1
  • 1
Samsdram
  • 1,615
  • 15
  • 18