DB access using same syntax as local variables? Neat!
Datetime epoch in 1841? Ok, sure.
Stringly typed with literally no other types? Uh…
Appendix 7 on this page http://www.faqs.org/faqs/m-technology-faq/part2/ : runs screaming into the night
It had some neat ideas, some alright ideas that were reasonable in the context it was created for, and some absolute nightmare fuel.
Some very novel ideas for the time. I’m not a PL historian but can’t think of an earlier language with such a complex runtime to support it.
But, woof - no thanks to the stringly typing. The article under discussion treats this as a positive, saying it eliminates conversion and having to worry about it. I don’t believe that’s possible, and would bet my life savings that MUMPS interpreting a string as a number when the programmer didn’t intend it, or vice-versa, is a reasonably common class of bugs in MUMPS programs.
The tutorial seems really good, but I’m frustrated with parts like that (or the explanation on a lack of operator precedence) which try to frame a bad thing as a good thing.
In this sense it reads like the autobiography of a presidential candidate; written in a calculated way to minimize flaws.
Is it a bad thing? Or is it different?
I literally spray brackets about because Im not sure of the precedence.
Explicit over implicit is generally regarded as a good thing. Why is there a blind spot when this comes to operator precedence?
I don't know mumps very well, but this seems pretty straightforward if you put the primer next to it, and I am troubled by your (common!) reaction to alien technology...
> Stringly typed with literally no other types? Uh…
like this example here; SQLite made this choice too. Everyone knows about SQLite by now, right?
All types are strings when the user types them in, whether you are talking source code text, or the patient's weight in kilograms. Pretending you can have other types is something the source code of your application (or the language your application is written in) does.
This is something that makes total sense when you are thinking about things the right way (whatever that means), so when something makes you go "uh" try inverting this equation, and ask yourself, in what way (or under what circumstances) would this decision make sense?
That sort of thinking will get you the right ideas to understand everything else in the software world, and make you less avoidant about filling in the gaps in your own abilities.
> It had some neat ideas
Has. Multiuser support is still almost nonexistent in mainstream programming (and just recently starting to actually show up in SQL implementations!). And besides SQL, the most popular language with global variables you've might have heard of is perl. Understanding these ideas is still in the future.
Putting the ideas in the past, and framing them with such harsh judgement -- especially the ideas like this that you don't fully understand yet -- keeps them out of your mind, and denies you access to what these ideas can do for you.
As an example: A lot of people make a "users" table in SQL for the users of their application. Of course most SQL implementations have "users" of their own, and have a robust implementation that is already there, and yet almost nobody uses it and chooses to make their own rather than learn how to use the one SQL gives them.
Now: SQL exfiltrations are only possible because of this, and when you fully understand why that is you'll probably never make another users table again.
> and some absolute nightmare fuel.
but nightmares? Seriously? There was nothing in that example code that I am going to have nightmares about. It seems very well thought out (unlike say, Python's). It's even Y2K compliant. There is even a few ideas in there I'm going to steal for my own parser.
There is good stuff here; don't give up.
I was alone in a room with one of my interviewers, who seemed pretty sharp. I asked him "do you like working here?"
He looked at me, glanced at the closed door, leaned forward and said in a low voice "nobody likes working here. If you have another option, take it."
I thanked him and left and I'm very glad I did.
At least the front end is much more modern.
A few years ago, they _did_ develop a TypeScript wrapper framework (which was transpiled down into MUMPS). They heavily encouraged newer application code to use this, but it never caught on, was quietly abandoned after a bit.
Internally, MUMPS was often criticized or laughed at, but I doubt it’s going anywhere anytime soon.
Also, the marketing term was post-relational if I recall correctly, the funny thing about that being that it was really pre-relational at first. Also, I forgot, it was IRIS this AOC stuff runs on - the $ZV actually needs that "R" in IRIS so it knows what label to jump to... and what file mode to use... it's wonderfully cursed ;P
That said, it doesn't hold a candle compared to this: https://stackoverflow.com/questions/4151554/need-mumps-sampl... which is just about the best obscured (or byte-saving rather) MUMPS snippet in existence.
One thing I miss about Caché/Ensemble/IRIS is the three different paradigms for manipulating the same bits of data - the whole object layer, SQL (with pre-compiled embedded SQL an option), and the raw global access.
MUMPS code is more readable than most languages, it’s very simple and procedural. And the ability to interact directly with durable data the same as you do local data is very nice. I don’t know why no modern languages try to do something similar.
Perl is modern (-ish? Definitely modern compared to MUMPS) and had "tie" for database access forever [0]
Python's dbm interface also looks like a regular dict [1]. I am sure there are many others, I know we had one "magic dict" in one of my work projects.
It's just that transparent access has some limitations, like lack of transactions, unexpected latency, lack of strong types, inability to only change a single value.
I've never been quite brave enough to try to build something with it.
You life, quite literally if you find yourself in a hospital, depends on MUMPS.
The second largest competitor, Cerner/Oracle Millenium, runs on MSFT SQL, and it's on life support. Last I heard, Oracle was looking to unload it.
I thought I was going into informatics to write code. It's politics as far as the eye can see.
Intentional?
For those unfamiliar, MUMPS is an imperative language famously born at Massachusetts General Hospital in 1966. Its defining characteristic is that the language and the database are deeply integrated, acting as an early NoSQL database decades before the term existed.
See here for more information about the project: https://github.com/rochus-keller/mumps/
There are pre-compiled versions of my MUMPS 76 interpreter in case you want to play with it.
It's about a Smalltalk-80 image from 1983.
Trellis/Owl had interesting ideas, though I spent more time with Modula-3.
In 1976, the year of the first standard, massive hospitals with thousands of patients run on MUMPS, on PDP machines with 8K to 24K of core memory and many concurrent users.
MUMPS is easy to read, understand and maintain when written well.
These examples (and the Wikipedia ones) are from code written when hospitals needed to run their whole EMR with extreme storage constraints, so more terse code was necessary to fit more on the disk. Of course they aren’t readable by modern standards.
Good times
M allows one to code in a very terse language (an artifact of only 2K RAM/ transient temporary memory) with so many abbreviations and short forms for intrinsic/builtin functions, variables, commands, and other things. A large number of string manipulation, mathematical, and logical functions with a form of string recognition matching (from SNOBOL) and type coercion/interpretation round out the basic expression evaluation system. Allowing variable names as valid values for any variable gives a way to create dynamic expressions and symbolic manipulation.
A fixed point numeric value with over 18 digits of accuracy means math on values over the national debt can be stored in a single variable. Lossy floating point systems of other computer languages are not acceptable to customers. Limits on strings of characters depend on implementations and have been only increasing over the years beyond megabytes. All of these are managed without applications dealing with pointer arithmetic, allocation, deallocation, and such schemes such as Rust, C++, require.
The decision to separate out I/O into a subsystem was very common at the time, with various kinds of devices providing a high level model of channels & streams that are all managed below the language implementation level. Tight limits and timing for input I/O and output I/O means no buffer overflow exploits. Character set management also keeps control over contents of strings.
Generally, M has follows the model of high level capabilities under a very simple language interface. Each command has a highly focused syntax.
Which is why permanent storage uses a dynamic sparse variable indexed by strings whose stored values are strings and is indicated using the caret ^ as the prefix to the variable name. This approach removed the need for user level applications to track disk latency, disk buffers, asynchronous processes, etc. which were common at that time.
Interprocess communication and control using a hierarchical Locking mechanism is very flexible. This means coordinating by locking a high level entry in the hierarchy and allow other worker processes to lock lower in the hierarchy.
The 1977 standard used a system that prevents deadlock from occurring. Later M Standards broadened the tools available with incremental & decremental locking and now deadlock can happen.
Transaction Processing allows one to separate data updates in a transparent way so competing control flows can more intelligently change the system. Basically, this allows a try-retry-commit-stop backtracking command flow similar to Prolog and declarative code.
Control flow also uses the parallel invocation command (JOB) and normal subroutine calls (DO), with parameter passing and function return values. Looping is unified by the FOR command. Exception processing and control flow avoid undefined behavior.
Dynamic variable lifetimes using KILL and the NEW commands and associative memory access to values of variables. Typed controlled run time evaluation of commands adds discipline beyond "eval" in other languages.
The language allows implementations to specify unique abilities to increase unique commercial subsystems while still being backward compatible. There are ways to invoke external code which can enhance capabilities as well as tieing to SQL and other languages.
While not part of the standard, high performance and reliable database management with ability to automatically recover from power loss using internal logging and rebuild tools, and compressed B*-trees is necessary for any M system to be viable in the market.