The Mumps Programming Language
cs.uni.edu
cs.uni.edu
From what I can remember:
-Only global variables
-Variables must only be capital letters, maximum length 6. If you run out of variables, you must cleverly use them in a routine and set them back to what they are. This means you can't use a name like myVar - you use AAAFD, ZBVCXZ, etc.
-System functions are usually things like ., >, ', ], so code looks like .'AAAF]{\;:..
-Meditech writes all of their own languages, databases, operating systems, tools, etc. You can only write in a non-Meditech language if you get approval from a multi-tiered architectural design board, which barely ever happens
-The founder hated C with undying passion. No one is ever allowed to use C
-All programming hires go through a 6 to 12 month training process to learn the tools, languages, and systems. As they almost exclusively hire non-CS majors, such as math and physics majors, they don't typically have a programming background and don't realize how bizarre the MediTech stack is
Because MediTech engineers get experience in a proprietary suite of technologies that is only used there, it is extremely difficult for them to get new jobs at the same pay grade and experience level. 5 years at MediTech is worth 0 years anywhere else. However, I have hired a few of these people, and while they knew nothing about say Python, JS, Linux, etc. when hired, their deep understanding of how computers work made them very skilled once they picked up the modern technologies. Not many engineers program for years in low-level nightmare languages before touching JavaScript or Python, most start high-level and go lower. The foundation provided by working in a language like Magic makes them know computers at a deeper level than most.
I swear it was something insane like 36k a year in 2005. compared to 55k for GS . I asked them if it came with something to offset that like a pension or housing and they looked at me like I was crazy. I asked them to explain what they had to offer me and they made some stuff up about it being a great job with advancement potential. I think the word loyalty may have come up.
I didn't get an offer not that I would have said yes.
The lobby was nice as I recall. Lot's of open space, granite, and flowing water. Maybe that makes it worthwhile? Oh and you have to wear dress clothes. On 36k a year.
I'm sure it depends on geography and living cost but 36k is very low imo for a private company.
Public companies such as public university, government, and such still pay a bit above that on top of good compensations (healthcare, vacations, etc...).
This is USA of course.
France in general could be different in term of tax, healthcare, etc...
[1]aside from being a long-suffering user of Meditech, I am also a long-suffering user of Epic, who had the misfortune of going through "mandatory Epic training" at 4 separate institutions that were transitioning to it from Meditech, or pencil and paper. I am still not sure which of the three systems were the most technologically advanced...
The fact that they're moving away from VB6 to a web-based front-end in 2017 should be reason enough to assume that whatever they come out with is going to be excruciating.
but web doesn't necessarily mean modern in any sense of the word.
Great food, cool campus, and I really liked Madison - just not what I was looking for.
This assumes that everyone's skill level is fixed coming out of college, and that the interview process doesn't produce false negatives to let people fall through the cracks.
Those are both really unfortunate assumptions.
The fact that the system works at all is total magic to me, with hundreds of subsystems and millions of lines of code, all with the same shared global variable pool. I remember having to spend a few days digging through hundreds of pages of kernel documentation (it has its own kernel!) to simply find out how to write to a file..
What you can remember seems largely correct. I think commands and syntax were case insensitive, and variables were case sensitive too? All kinds of insanity like that.
He's very much a Meditech lifer, and at this point may have been there for ~20 years at this point. From where he started, it was a big step up. Though what he could've done after his first 7 years at the place, I can only imagine, if he simply put in the effort to go anywhere else.
Proprietary language concerns aside, it was fascinating using the tech there. Backend was Magic, as described by you and others. Direct B-Tree manipulation meant I didn't learn about the relational model but learned to reason about performance and indexing very directly.
The front-end language was what I found particularly fascinating though. It was concatenative, along the lines of Forth, and had some fairly powerful functional constructs, like a multi-part IF/Case where the first true expression would be returned to the outer scope.
Stuff was stringly-typed everywhere I remember, and with little to no safety on anything - I once found a bug where adding 1 to a list caused the ending delimiter to become something else and the list became unbounded in memory.
Awesome languages to write in, terrible to debug.
- Recursion was absolutely NOT ALLOWED because of 'the risk of crashes.'
Some more info on them (edit: added more as I remembered them)
During my last interview, they had me read my job responsibilities and then write an essay, in front of them, "in my own words" of what I would be doing. My future manager slowly walked around the perimeter of the room reading the essay while I sat in awkward silence. I still have no idea why this was necessary.
My salary was 38,000, my boss went home after my yearly review, then called my desk phone to say "money is tight this year" so I wouldn't be getting a raise.
There was a bonus you would get each Christmas which was a small percent of your yearly salary (5%?) which was compounded each year up to the last five years. Their first few weeks of training, they have lifers come in and openly brag about their yearly bonuses, which are only really impressive if you've been there for fifteen to twenty years.
One time the CEO came down to the cafe (they make food on-campus at most of their locations) to make an appearance, and magnanimously waved people through the line - he was paying for our lunches! Money being extremely tight as a new hire, I made my way through the line, but he had decided that he had paid for enough - he held up his hand and said 'sorry' and walked off. :(
Around the end of our training, the CEO had the latest batch of new hires head down to the auditorium where he gave us a speech reminiscent of cliche multi-level marketing summit speeches, and the only question asked afterward was by a really brave girl who asked him why our wages weren't competitive with the rest of the job market. He seemed really flustered and just answered "we think they're competitive, and if someone thinks they aren't, they're toxic and will no longer be employed here." I never saw her again.
Knowing the exact size of your stack statically is hugely important in safety-critical software.
This is plain incompetence on the "language" developers.
"When it is worth considering breaking up a monolith app into micro services?"
"About 1500 variables from now"
Now you have my curiosity piqued. When I went to their Wikipedia entry [1], I saw that their server only runs on top of Windows. You said they run their own OS, so does that mean they effectively run an emulator of their OS on top of Windows? And if they hate C, does that mean MAGIC is self-targetable, or there is a very, very tiny chunk of C within Meditech, or that they develop in assembler to bootstrap their emulator?
An entire OS written in a Mumps dialect and a half-billion dollar company built around it (replete with an ecosystem of consulting companies) or TempleOS [2] vie in my mind for about the same uniqueness level.
[1] https://en.wikipedia.org/wiki/Meditech
[2] https://motherboard.vice.com/en_us/article/gods-lonely-progr...
They then changed over to everything running as services under Windows servers, including a wacky append-only plaintext file system for audit logs.
I used to support their scanning and archiving stuff, which mostly meant fixing the horrible layers of Windows folder permissions on various Windows versions.
What's very frustrating is that no one - EMR vendors, hospitals, or even doctors - seem to realize just how much of a productivity booster good UX design can be. Even the ability to have multiple windows open at once (i.e. the ability to look at lab results while writing orders or a progress note) would be a breath of fresh air.
You have the hospital administration that cares about billing first and foremost. Then you have doctors who have 500 lb egos and could give a shit about the computer systems.
All the company has to do is sell regional hospitals and the smaller practices will fall in line to more easily interact with the health network.
When my wife had our baby, we were in the hospital for a few days due to some complications. The OB nurses rolled around carts with two thin clients and two PCs on a KVM. There were seperate systems for charting, pharmacy, special OB charting, and something else. It was ridiculous.
I think MUMPS was closely tied to VAX VMS at one point. I'm sure HP (Compaq (DEC)) still makes MUMPS money from OpenVMS.
And holy hell, they hate medtech. They're actually quite happy with the functionality, but hate the interface. I had one nurse who went out of her way to contact them asking to make the smallest change, which would improve her job heaps - nearly a year later, no updates.
Thing is, these institutions are in a hard place. MedTech is shitty, but works, and changing to another system is such a huge task, why bother. Beyond that, if the majority of healthcare institutions are also in the same boat, so why go against the grain.
Healthcare software is weird man.
EDIT: I got meditech confused with medtech, my bad. Medtech still sucks.
- virtualization
- support of vmware VMDK files instead of RDM
- support for non EMC arrays
- support for hyperconverged (nutanix)
- support for non EMC Networker or BridgeHead Backup
- DR process not using some proprietary software
- file archiving not using proprietary tool
version 5.x was a 3 tier application that looked like Windows 3.1 version 6.x no longer required 3 tier, not because they fixed it but just required you to run Citrix and UI was similar to GUI being put on top of AS/400 green screens (menu system) ... have a look here if you dare :) http://webapp.cchcs.org/tutorials/CBT/ADM/ADM%20Registration...
Apparently they are working on a SQL port and we advocated for years that they should focus on the business side using industry standard tools and languages. I'm not hopeful tho as they wouldn't support things like Windows VSS and built their own tool, still had multiple single points of failures (20 "File Servers" aka the database backend and none redundant), issues with NTFS FAL fragmentation (and associated requirement to get a third party tool to monitor and fix) and the list goes on...
Moved on recently and only thing that looks good on the resume is, for people knowing Meditech, seeing all the changes we were able to push through ...
Oh and yes users were not big fans. All data entry needs to be entered in CAPITAL (no auto convert) so you need to caps lock when in Meditech and then remove the lock when switching to something like Word and the spacebar is a keyboard shortcut to select an item ...
And to really appreciated how bad it is, just search for "Meditech sucks" and read feedback from nurses ...
Back to the original post, I put MUMPS in the same category as COBOL ... useful a long time ago.
That's fascinating to hear. One of the key factors I heard that the EHR/EMR industry converged upon M is because patient records are sparse data efficiently represented in a key-value database, but which mapped inefficiently to SQL. The example given to me was a patient schema represented in SQL could literally have tens of thousands of columns/fields, of which only several hundred were used for each specific patient. Was the explanation given to me incorrect, or has the situation in the industry changed?
There are modern ANSI standards for the language, and several private vendors and open source implementations.
There are 2 things I like about M:
1. It has limited commands and is whitespace-aware - Newer developers can jump right into M, precisely because it lacks higher-level abstractions like first-class functions or closures. It's easy to memorize the standard library and easy to read code (because it's whitespace sensitive like Python).
2. The NoSQL database built right into the code - You access the built-in, persistent database the same way you access regular data structures. When setting values into an array you do something like "set foo(bar)=1". In order to persist that same data to disk, you just do set ^foo(bar)=1. This means less worrying about query languages and ORMs.
The database is a sparse B-tree structure so it's wicked fast at reads and writes. Great for a fast key-value store. There are people using M's battle-hardened NoSQL database with Node.js drivers, and you're very unlikely to find a bug because it's been in production so long. This makes it good for mission-critical applications like healthcare and finance.
Check out Rob Tweed's work with M: https://robtweed.wordpress.com/2012/10/24/i-have-seen-the-fu...
I know people that love working in COBOL. For the most part that is because it is what they know. Do you have extensive experience with other platforms/languages? How do you rate them side-by-side?
> and you're very unlikely to find a bug because it's been in production so long.
This goes for anything that's old. But that does not equate to 'good', it's just old. Just like new isn't necessarily better old isn't either.
And there are usually plenty of bugs in those codebases, just not in the runtime. But the user supplied code usually pre-dates any kind of automated (or even at all) testing other than 'try stuff and see if it produces the right results'.
The MUMPS codebase I worked on in the 80's was so fragile that deleting a single global string could cause the whole system to break down in ways that required a restore from backups. Don't ask me how I know that ;)
The fun part about Mumps is that it's basically Lisp's ugly sibling, without meaningful scoping rules. You can easily do lots of terrible things in Mumps, but those things are usually more straightforward than the terrible things you do in other languages. You can also do elegant things, though a little less straightforwardly.
My single biggest complaint about Mumps codebases is that they're usually old, which means they have shitty documentation. Not that new ones are necessarily any better, but at least there's a chance new things are written in Orgmode or something :)
I'd love to see how it should be done, the only things I've seen are examples of how things (any things!) really should not be done.
I'm not really criticizing because I'm not sure there's an elegant way to do it, but I fled screaming.
Thanks for proving without a doubt that Mumps belongs in the trash can
Forth is old too and some people love it.
Both MUMPS and Forth have some unique features:
- easy to bootstrap for Forth (mixing a compiler and interpreter)
- persistent and associative arrays for MUMPS
For me, MUMPS is also related to some aspects of Erlang.
Superficially, yes. They're both old and they both have ways of hooking machines together at a distance built right into the fabric of the language.
But that's where all analogies end. A MUMPS program tends to be an unreadable mess to anybody who hasn't touched it in the last 30 seconds, whereas Erlang is really quite readable (though there are many people bitching at the syntax, this usually means they haven't spent any time with the language). Erlang projects tend to exhibit extreme levels of reliability and fault tolerance (and fault resistance) whereas MUMPS installations tend to be houses of cards that come crashing down with the first breath of wind.
You could not - outside of superficial similarities - find two architectures so diametrically opposed as MUMPS and Erlang.
Seems to me it's a matter of how well it was written and the experience of the reader.
Kind of like other languages.
It's not the old part that he's praising but the fact that it's been extensively tested. That's definitely a plus.
Yes, but that 'plus' is largely negated by the huge minuses of the language itself to the point that you would probably produce something a lot more reliable by using something less battle tested and newer, and besides that there are other options that just as battle tested or even more so and better so why settle for less? (Erlang, for instance)
Have you ever used Erlang? If so, how would you compare MUMPS' tables to Erlang's ETS/DETS tables?
2. It would be trivial to implement a key-val data structure that is persisted to disk in almost any nice modern language. And there are very good No-SQL key-val stores to choose from that are backed by very large and credible industries.
The Node.js drivers. Are you sure those are not mainly due to legacy integrations rather than "we really just wanted to use the MUMPS db" ?
> It has limited commands and is whitespace-aware
Limited commands to a certain extent just means a more dangerous language. Being able to give functions private scope is something that's really important to me personally, as is having named constants, and objects with methods. About whitespace awareness, I consider it a fascinating design choice that the difference between one or two spaces between tokens within the same line of code can mean different things.
> Newer developers can jump right into M, precisely because it lacks higher-level abstractions like first-class functions or closures.
The language does not support first-class functions, but it does support the "xecute" command for running arbitrary code strings, which is particularly risky if you ever use user inputs as parameters in the strings you try to xecute.
Also, I primarily want knowledgeable developers working on my healthcare and financial systems, not the newer ones who would somehow be incapable of using a first-class function.
> wicked fast at reads and writes. Great for a fast key-value store.
This isn't a differentiating feature.
> you're very unlikely to find a bug because it's been in production so long. This makes it good for mission-critical applications like healthcare and finance.
What happens when you need to change the code? Do you wait a long time until bugs are no longer found?
I think that fast reads/writes actually are a reasonably differentiating feature--if you want something like that in JS, Python, .... you're going to have to drop down to a C extension, and you'll have to put a lot of effort into that being portable. In a MUMPS interpreter, it's already there and it already works reliably.
I am actually not able to find statistics matching up M databases with non-M databases at the moment, but I'd be interested in seeing something like that. I don't know what you mean about having to roll your own C extension to talk to your database.
The biggest difference, it seems, is that instead of key-value stores, you had indexed tables. However, indexes were effectively key maps - there was no SELECT as in SQL (well, there was eventually, but not at first); instead you explicitly specified the index to use - unless you used the default index for that table - and performed a lookup, and it would position the current cursor for that table to the appropriate record. You would then access fields of that record as regular variables:
https://msdn.microsoft.com/ru-ru/library/bz5ys9dy(v=vs.80).a...
It might sound weird, but it actually worked really well for stereotypical CRUD form-based desktop apps - your cursor corresponds to the record currently being edited/displayed.
I'm very, very happy to not be using this language anymore. After my first year on the job, I read some JavaScript code, and I nearly wept at how comparatively beautiful it was.
"Some of the contention arose in response to strong M advocacy on the part of one commercial interest, InterSystems, whose chief executive disliked the name MUMPS and felt that it represented a serious marketing obstacle. Thus, favoring M to some extent became identified as alignment with InterSystems."
That's all the convincing I'd ever need. Though having a built-in optionally-persistent B-tree-based store sounds interesting.
SQLite will still perform better though, "heavyweight" SQL syntax notwithstanding.
I found Epic MUMPS to be remarkably readable. Lots and lots of documentation, quite consistent coding standards, and although I would have preferred to write SQL queries rather than MUMPS routines, I didn't find it that abhorrent.
If a job description contains the word 'Mumps' and it is not in a sentence about your medical history: run like hell unless you are starving.
Source: was a Mumps programmer long long ago in a short stint at a bank that fortunately got bought out by another bank which had saner ideas about automation.
I worked as a civil servant in such a tribunal. Mumps was the first programming language I used professionally - in 2009! I wrote M for a living for around a year. It's still being heavily used in the place I worked at. My colleagues, who were more senior than I by a few decades, had written hundreds of thousands (millions?) of LOC in Mumps and developed a rich ecosystem of internal tools and libraries for it. It was a bit scary to do maintenance work on code that was written in the 80s, but I could often look at the author's signature and find out he was sitting right beside me - still pumping out Mumps. :-)
I can't say I loved the language, but it has some interesting concepts and reading about it makes me feel nostalgic.
Something weird about Mumps that I didn't see others mentioning here is how common it is for M programmers to abbreviate commands. Every command in Mumps can be abbreviated; "w" for "write", "i" for "if"; "s" for "set" and so on. This causes code to be extremely terse, and hard to understand for a beginner. A very simple example:
> I ($G(^ATM(1000))+$G(^ATM(500))+$G(^ATM(100)))<=0 D
> . W #,!,"There is no money available in this Machine. Sorry for the inconvenience."
> . Q
It gets way more complicated than that. After reading this kind of code for a few months, you get really good at parsing it.
This must be how APL language users feel parsing their ultra-terse syntaxes (includes J/K/Q variants). Seems most applicable to quant shops that still use kdb+.
Interestingly, the source code for VistA has been obtained via FOIA requests and so the code is available in the public domain[1]. There are now forks of VistA, like OpenVista.
At one point we had to argue with Github to support syntax highlighting for M/MUMPS: https://github.com/github/linguist/pull/148
[0] https://en.wikipedia.org/wiki/VistA [1] https://en.wikipedia.org/wiki/VistA#Usage_in_non-governmenta...
The actual size of the source code.
As the codebase grew, they had to shrink down the code to be able to fit it all in. Comments were the first to go. The end result was single letter variable and function names. The code was impenetrable!
Presumably this is no longer a limitation :)
Just one snippet from the User's Guide:
If you use a goto command, all do command pending returns
are canceled. That is if you invoke a section of code by
means of a do and the section of code executes a goto
command, the return to the line the do was on is canceled
as well as any other pending returns.
Even BASIC does better than that.Yes, basic did better than that but you can actually 'goto' into some line in another subroutine in BASIC which can cause all kinds of interesting results (usually not the ones you intended though).
Look at the documentation for the "shared" statement: http://www.leinweb.com/basic/manual/
It's a pretty nice language.
Maybe the article would be better if he showed this more beautiful way of writing MUMPS?
MUMPS is older than SQL, so preSQL might be more appropriate than NoSQL.
There were moments of joy programming M, and the performance, scalability, and HA aspects of the Intersystems implementation don't hurt Epic one bit in the sales process.
At Epic, there are so many abstractions away from M that you might start to think you're working in another language. You never set globals in production code, instead using Epic's homegrown ORM to define schemas for your data.
At the end of the day, lack of first order functions and any other data structure other than the B-tree array makes for fun problem solving, but not necessarily clean and concise code.
(You're telling me though you never came across "end-user" API-level code that was directly digging around in ^ER, ^ER1? Hahah)
If Chronicles was open sourced tomorrow, it probably wouldn't make the front page of HN, but it is extremely feature rich tool that fits perfectly into the Epic ecosystem. That's true of most things that Epic develops.
"The M database is a key-value database engine optimized for high-throughput transaction processing. As such it is in the class of "schema-less", "schema-free," or NoSQL databases. Internally, M stores data in multidimensional hierarchical sparse arrays (also known as key-value nodes, sub-trees, or associative memory). Each array may have up to 32 subscripts, or dimensions. A scalar can be thought of as an array element with zero subscripts. Nodes with varying numbers of subscripts (including one node with no subscripts) can freely co-exist in the same array." [1]
I had to work with MUMPS once in the past when I was working in the green-screen world in healthcare. I also had to work with Pick/D3 and Basic. It was kind of nice to start there, then move to relational databases, and then see the world get excited again in older models of databases with the NoSQL movement (albeit, much more scalable and distributed).
Yep. And then there were the clustering primitives allowing you to modify variables on other machines. Which takes 'global state' to a wholly different level.
You thought it was problematic that a function could change a global variable as a side effect. Wait until you have to debug that global variable changing out from under your feet by a program running on a machine half the continent away.
Do you have a preference on NoSQL vs relational databases?
The latest generation of NoSQL databases really tried to add to the distributed / scalability story of databases, as well as provide simpler "input", "output" and "storage mechanisms". This, often at the cost of a degree of ease of use of query languages to be able to easily analyze data.
As NoSQL movement started to come into focus, folks saw that the then dominant traditional relational / ACID model was not scaling to internet scale (too many JOINs, too hard to do ACID at that size or not needed, etc.). In reaction to "internet scale", the search turned to finding new or innovative alternatives to the relational model (which really, just represented what was the state of the art at the time). This is how we got BASE instead of ACID, and went back to key-value.. or document-oriented.. or graph-based... or Hadoop/Map-Reduce, etc. People exploring lots of alternatives.
I think people mentally "threw relational databases out" for a while as quickly as they threw out the other alternatives (the precursors to relational databases), when relational databases came along. Many have found it hard to live without relational databases.
I think modern NoSQL databases try to maximize on input/output/storage and distribution / MPP of data. By now, they give some more expressiveness for query (like MongoDB, Cassandra, Hive/Impala in the Hadoop world), although SQL still beats them in my opinion for ease of use. SQL also could have advanced as the query interface for those systems too, and if you look at the SQL:2011 standard, you'll see that it included methods for querying things that are distinctly "non-relational" (multivalue fields, etc.).
NoSQL databases also more cleanly map to object models, the dominant programming paradigm (although who knows, maybe one day that too shall change).
No, I don't have a preference of NoSQL vs relational databases in general. I believe they are complementary and maybe there isn't such a thing as a general purpose database for every use case. I do believe in the old saying, "try to use the right tool for the job". There are cases when a NoSQL database works superbly, and others where a relational database just feels right. For example, storing "objects" quickly works well with a NoSQL database vs. querying for a denormalized data warehouse seems to fit well into a relational database (ironically of course, since they are often denormalized and not third-normal-form 3NF).
Anyway, that's my take... but anyone else who has input should feel free to chime in.
The most important part about any computing system/language is the resulting application. Yes, it is nicer for programmers when they have advanced language features. But ultimately, the test of how "good" a language is should really be about how useful it is, and how widely it is used.
The wheel is very old technology and yet still very important.
I worked with the MUMPS Standard Committee trying make the language better while simultaneously trying to minimize the problems moving the large base of existing code to the new Standard MUMPS. MUMPS was filled with hidden gotchas. For example, in some early versions, trailing blanks in statements were significant.
The Wikipedia MUMPS article (https://en.wikipedia.org/wiki/MUMPS) provides some insight into the language and its genesis. The inclusion of a key-value store embedded into the language was a significant innovation and helped the language to be successful.
Took Database Systems from Dr. O'Kane. He was a pretty fun professor.
Forget the Mumps language which always ends up being criticised for all manner of reasons, as witnessed here already.
Check out the database, however - it's the hidden treasure, which sadly gets overlooked and dismissed because of conflation with the Mumps language and its poisonous baggage.
You don't need the Mumps language to access the database. My work with it these days is in JavaScript/Node.js, using it purely as a multi-model NoSQL database, accessed in-process.
Check out what can be done with it here: http://ec2.mgateway.com/ewd/ws/training.html
In particular check out the multi-model capabilities of the database and the JavaScript-orientated abstractions that are possible - see parts 17 - 27.
Some may also find this interesting: https://github.com/robtweed/ewd-redis-globals
I got a pretty persistent request to work on an informix 4gl system for a ridiculous rate. Haven't touched the stuff in years.
Most COBOL is cut and paste. One guy I know basically reads books and updates some report, where update means enter the next month and year combination into some code, entering a change request, and go to a change meeting.
He's basically working for 3 years until his wife can retire, then building a lake house.
</shudder>
It was about 3 years too long. Yes, that math is correct.
As far as I recall, MUMPS is essentially the dedicated coding language for a b-tree based database, and the only reason to ever use it for anything is for processing huge numbers of transactions through your NoSQL database every second, forever. I guess you also might want it if none of your employees knew how to correctly normalize a relational database.
Other than the nightmarish accumulation of technical debt continually rolled over since 1979, and the ungodly high turnover of people jumping ship after realizing MUMPS was a golden ball-and-chain, it was a pretty nice place to work. But management had a culture that it needed to force down everyone's throats, and the tech stack was a real resume killer. I still get contacted by recruiters desperate for MUMPS developers, and they make me feel like someone trapped inside a house besieged by zombies. I get really quiet, and hope they don't break any windows.
It only works because they throw a huge amount of money at it, and no one has any incentive to cheap out on medical management software.
Since I was more in their systems department I had limited opportunity to observe their archaic superstitions about code structure, but the short introduction course to M they provided confirmed that most current and new employees were willing to accept that certain control flow tools or function structures were dangerous because they were necessarily slower than something that made sense in hand assembly programming, since there had obviously been no developments in compiler optimization since M was designed (in the good old days, before C existed).
You weren't even allowed to touch the infrastructural M code. Mostly, you worked on superficial or peripheral M code, or on the GUI in VB6. I heard rumors of a GUI modernization team, but never saw any direct evidence of it.
It was a result of the iron grip of the top management. They didn't want to yield control of the company to the people actually running it. You were expected to use your expertise to do what you were told to do, in the best way you could, while still remaining completely within your lane.
After the 6 months of training, I gave it a year to read the character of the company, and then another 6 months to soak some potentially major family health care costs with that sweet insurance plan, then spent 4 months job hunting. It was the best employer-offered health insurance plan I ever had.
But make no mistake. Companies like Epic are why health care costs in the US are huge and growing. Epic never refactors anything that still works well enough to hold together with some expensive human labor. It is a technology company that runs on well-trained people instead of well-designed code and processes.
Some functional areas use Hadoop and SQL now. New server development can be done in VisualStudio using Typescript (which gets converted to M).
There are automated tools to set and verify OS parameters.
Most new installs are Linux now. No one uses VMS today. HP-UX and Solaris will be out of use in a couple years. InterSystems licensing is why people continue to use AIX (you have to buy new licenses to switch from AIX to Linux).
See the intersystems cache talk page on wikipedia: https://en.wikipedia.org/wiki/Talk:InterSystems_Cach%C3%A9
That's the summer I decided I didn't want to be a programmer.
Ex:
>set array("node1")="Hello"
>set array("node1","subNode1")="Hola"
>set array("node1","subNodeX")="Howdy"
>set array("node2")=39481
>set array(19849,1,1,1,3,"Godzilla",5,8)="Greetings"
All dynamically created on the fly - no need to define the array in any way ahead of time! The nodes are also automatically sorted after any addition/deletion.Looping over the arrays is very easy too. M has a function that lets you set a variable to the next node.
Ex. (using the above example):
>set foo=$O(array(foo)) - result: foo="node1"
>set foo=$O(array(foo)) - result: foo="node2"
>kill foo
>set foo=$O(array(foo)) - result: foo="node1"
>set bar=$O(array(foo,bar) - result: bar="subNode1"
>set output=array(foo,bar) - result: output="Hello"
>set bar=$O(array(food,bar) - result: bar="subNodeX"
Variables can also be created on the fly, and don't need to be defined as a type ahead of time. (Technically you don't define them ahead of time at all, if you want a new variable just set it to something!) They can be strings or numbers, and you can change their type at any time by setting them to a new value.Pretty cool, and particularly easy for someone with no coding experience to pick up. I'd only ever use it for managing a database, though.
It was baffling in spots, but the M database was kind of neat. Overall, someone else in this thread said it best "You can easily do lots of terrible things in Mumps, but those things are usually more straightforward than the terrible things you do in other languages. You can also do elegant things, though a little less straightforwardly."
https://github.com/robtweed/node-mdb/blob/master/gtm/MDB.m#L...
It ran on a VAX 11/751 that was maxed out with 8 MB (yes, that's megabytes) of RAM and a state of the art Fujitsu Eagle 400 MB (yes, that's megabytes) 14" hard drive. The user interface was text-based forms on VT-100 terminals.
M/VX was selected because there was nothing available at the time that could look up data nearly as fast as the M/VX B-Tree database, and we had to look up a lot of map coordinates.
I wouldn't grace the data storage with a description of NoSQL - it was plain and simply a multi-rooted hierarchical database, or less fancily, a set of multidimensional disk-based associative arrays. As others have pointed out, it differed syntactically from a memory-based array only by being prefixed with a caret/circumflex (^). It certainly was damn fast (for the day).
Initially, it was so cool to be able to store something just by writing
set ^address("US","FL","Miami","Main St",12345)=1
But the pain soon set in.There were no such things as indexes. We had to create (and maintain) inverted arrays for that purpose.
If we got the hierarchy wrong, it was murder to reorganize it. Queries were only really possible if they fit into an existing hierarchy.
There was really no such thing as an ad-hoc query.
Hmm, maybe it was kind of like NoSQL...
But the killer feature (as in, it killed us over and over) was falling foul of the hideous global variable, $test, as others have pointed out.
I don't remember clearly, but if you wrote something like
set a=1
set b=0
if a=1 open 1:"input.txt",old
else set b=10
the value of b after this would be 0 if "input.txt" could be opened, and 10 if not. This is because open set $test to false if it fails, so the else executes, even though a=1... the horror, the horror....Oh, oh, oh... and the result of 2+35 would be 25, not 17, because there was no operator precedence. You had* to use parentheses.
So it was kind of amazing in some ways (because ambulance dispatch system in 8MB of RAM) but a horror show in so many others. I'm glad it was only 2 years, and I did get to write some cool VAX PASCAL to allow M/VX to interface with the FEPs.
It is much nicer when the system remembers to do that for you.
There were gotchas in the language that required you to understand it and play ball its way. Not unlike other languages I've seen. The payback was trememdous flexibility and performance on minimal (for today) systems.
Mumps is now called M or cache but it was originally called Mumps.
See http://www.camta.net/aboutm.htm
; The following is a single line of code
beer ; Randy M. Hayman (haymanr@icefog.alaska.edu)
for i=99:-1:1 w !,i," bottle",$S(i=1:"",1:"s"),
" of beer on the wall, ",i," bottle",$S(i=1:"",1:"s"),
" of beer.",!,"Take one down, pass it around, ",
i-1," bottle",$S(i=2:"",1:"s")," of beer on the wall.",!
I've written compilers for GNU Make, and I've translated C into Perl, and that still makes my eyes bleed... so, as far as I can tell:Commands can be abbreviated down to a single letter, so w = WRITE. Multiple commands can be glued together with whitespace. Strings are as normal, but ' is the not operator. There is no => or <= operators; use `< or `> respectively. There is Javascript-esque dodgy implicit type conversion from strings to ints, but dodgier ("aa1"+1 is 1; "1aa"+1 is 2). Commands can be suffixed with a colon and a boolean expression and they'll be executed conditionally. $ precedes a function call. ! is the OR operator, except in a WRITE command where it prints a newline. The @ expression is the equivalent of eval(), and yes, all your local variables are in scope when it runs. $test contains the value of the conditional in the IF command most recently in scope (as distinct from conditional execution). ELSE is a statement which executes the rest of the line only if $test is 0. Putting IF and ELSE on the same line doesn't work (imaginary cookie for anyone who can guess why). An extra space is required between commands if the first command takes no arguments. Variables are global unless declare local.
I believe $S(...) is the equivalent of switch; $S(i=1:"",1:"s") contains two conditions; if i=1, then ""; otherwise if 1, "s" (1 is boolean true).
The break statement is called QUIT. The return statement is also called QUIT. The BREAK statement actually drops out to the debugger. The quit statement is actually called HALT. the sleep statement is called HANG.
If a global variable is preceded with a ^, it is persisted by name to the database; some versions have transactions. Arrays are key/value sets with many indices. The docs say that trees are common, using a syntax like ^mytree(path,to,tree,node,from,root). ...which is actually quite cool.
I am torn between admiration for people who can get useful work done in this, and horror that such a thing really exists in a non-ironic sense.
All that's from: https://www.cs.uni.edu/~okane/source/MUMPS-MDH/MumpsTutorial...
foo() ; declare function foo
n x ; declare variable x
s x=1 ; set x to 1
d bar() ; call bar
w x ; print x
q ; return
bar()
s x=5 ; set x to 5. Since x is not declared in this function's scope, it will search the symbol table of the calling function and overwrite its x
q
I've run into so many bugs caused by something like this.I'm actually kinda used to that; I grew up with BBC Basic, which behaves the same way:
10 i = 0
20 PROCtest1
30 END
40 :
50 DEF PROCtest1
60 LOCAL i
70 i = 1
80 PROCtest2
90 ENDPROC
100 :
110 DEF PROCtest2
120 PRINT i
130 ENDPROC
> RUN
1
...it occurs to me that BBC Basic, at least the later versions with block IFs, is a better language than Mumps in almost every way (except the integrated database stuff)!For my first 8 years I used a version called MIIS, which was developed by Meditech. MIIS allowed 2 KB symbol space per job and 2 KB code space. Amazingly we supported libraries, hospitals and laboratories. The hardware we used were DG Eclipse and MV minicomputers; however, it also ran on DEC PDP and IBM Series/1 machines. I remember hearing that the MV systems could hold 2 MB of RAM, but it was found that the 2nd MB didn't add much performance-wise. These systems supported dozens of printers and terminals.
Since then I have mostly used Digital Standard MUMPS (DSM) and Intersystems Cache and again this has been in support of medical information systems. These systems allowed for much larger memory partitions for each job. I coded CRUD applications, reports and interfaces (both with other computers and with automated instruments). I also developed inhouse web applications, using Cache's advanced object system and SQL interface.
MUMPS/Cache runs on everything from the Raspberry Pi to mainframes. I knew one guy who developed a multi-user accounting package that ran off of a PC-AT. I've never heard of another language that could operate in multi-user mode in such constrained conditions, except for Forth. Maybe C under Coherent? The ability to run on different architectures enabled lab info systems vendor, Sunquest, to increase their revenues by selling to clients who would only accept IBM hardware, where previously Sunquest had only sold DEC boxes. I don't believe much in the code had to be changed to facilitate the transfer to mainframes. Yet another lab systems vendor, Antrim, used Micronetics Standard MUMPS (MSM) on RS/6000 boxes. I worked on interfaces to automated lab instruments for Antrim.
While my first MUMPS implementation was from Meditech, I had a different experience from the individual who reported using Magic:
. MIIS had both global and local variables . I don't remember if variables had to be capital letters, but other versions did/do not have such a requirement . System functions were not so obtuse . Modern variations, such as Cache and maybe GT.M from FIS, allow communication with other languages
While the early versions of MUMPS did not support object-oriented code or graphical displays, they did support VT-220 style terminals and the displays were quite nice. This was in the early 80's. So while some companies produced products with roll and scroll, others supported formatted screens.
While MUMPS code looks odd to someone unacquainted with it, with a bit of use, it becomes obvious. This is nice because most of the code I've seen still uses single-character commands and 2 or 3-character function names. I really view this as a matter of experience: Haskell code looks like gibberish to me and I only understand a portion of Klong (which is patterned after K).
I had brief forays into COBOL and Fortran earlier in my career. And I determined I preferred MUMPS: It made lots of things easier and avoided some common problems in those other languages (such as moving too many spaces into a Fortran variable - which would both clear the variable and part of the program's code at the same time).
I really enjoy learning new languages and using them. I have coded a project using bash, awk, and Klong, which was a hoot for me. And they all have tricks which MUMPS does not have. Of course they are all just youngsters compared to this almost 50 year old language, too. And while it may not be the best language out there -- whatever that means -- it has powered libraries, credit unions, medical systems (including the Veteran's Administration which has one of the world's largest medical system), banks and stock brokers (TDAmeritrade). I hear even the European Space Agency is using it to map the heavens.
Perhaps most importantly to me, it has provided a means to feed and house my family and in my later years allowed me to be mobile, through working remotely (never even meeting my employer face to face). I imagine that it will continue to morph and serve the data processing needs of many as the years roll on.
Thanks for reading.
Steve