en en en pt es en en en en cv az en en en en en en en en en en en ca es en es ne en en en en en en en fr en en en en en en en en en en en en en en fr en en en en en en en en en en en en en en en en en en en zh nl en en en en en en en en en en en en en en it en en en en en en en pt en en en en en en en en en
These days, I spend most of my programming time working on the Higgs JavaScript JIT compiler for my thesis, and most of the code I write is in D. I don’t always take the time to write the best, most carefully engineered code, especially if I know I might rework a given piece of code later. Still, I try to pay some attention to generally-accepted-best-software-design-practices. One thing I try to pay special attention to is which data should be immutable and which shouldn’t. I write my code in an imperative language, but I too have come to accept that immutable data and immutable data structures can make a program safer and easier to debug.
The main thing I’m working on right now, for Higgs, is a system of shapes (aka hidden classes) to describe object layouts in memory. In the Higgs object system, JavaScript objects are essentially a flat list of slots which can contain values. Shapes are essentially a tree data structure, where each node describes a property in an object, and most importantly, where that property will be stored in a flat object layout (the slot index associated with that property). Each object has an associated pointer to a node in the shape tree. Through this shape node pointer, you can find the properties stored in that object, their names, and which slot you can find them at. The important thing is that the shape tree nodes are essentially immutable. Once such a node is created, the name of the property it describes, the associated slot index, and all other attributes of the node should never change.
As someone who wants to write safe, descriptive code, I wanted to explicitly express those immutability constraints in my code. I wanted to use const(ObjShape) pointers when manipulating shapes. I also wanted to make the fields of the ObjShape class themselves const. Unfortunately, this plan didn’t work out. The DMD compiler wasn’t having it. I quickly found out that the D programming language (which is quite like C++ in this regard) just didn’t offer a way to express the semantics I wanted. Introducing const or immutable keywords in the code introduced strange and unpredictable compiler errors. Struct objects that could be copied by value before couldn’t anymore. Some of the errors reported were entirely nonsensical problems I never saw coming.
Consider the following snippet, and the compiler error it produces
This is complete utter nonsense, and it deeply offends me! I specified that the parent field of class A should be constant. In D, you get “constness all the way down”, which means that I can’t mutate the parent field, and I also can’t mutate the object that the parent field points to. But, where in this program did I specify that the variable p was immutable and could not be redefined? Nowhere! This is problematic, because as far as I know, there is pretty much no way to write the type of p in such a way that p points to a const(A) object, but p remains mutable, not without ugly, unsafe type casting tricks. There’s no way to have a mutable variable that points to an immutable object? That’s insane!
In my opinion, C++ and D both lack expressivity when it comes to constness. D’s const and immutable keywords are is simply overpowering. It’s an issue in the other direction, too, because “constness all the way down” means that I can’t have a class field that’s immutable without also being forced to assume that the object pointed to by the field is entirely immutable. That’s not necessarily what I want. In the end, I’ve been forced to give up and remove const keywords on many occasions, because I end up fighting with the type system too much, it’s getting in my way.
It’s good that modern imperative languages have some tools to express purity and immutability. However, I think that there’s an issue of granularity. There are ways in which it makes sense to talk about constness, and ways in which it doesn’t. I’d almost say that I prefer JavaScript’s notion of constness, because it’s much simpler. In JavaScript, you can make an object property constant, but what that field points to does not have to be immutable. That is all! This might seem primitive, since you’re only able to painstakingly mark constness on individual object properties one at a time. It might feel like the only tool you have to deal with immutability in JavaScript is a tiny toothpick. This, however, is forgetting that JS has powerful introspection capabilities which allow to write code that makes an entire data structure immutable with a single function call. The language offers you the tools to express constness any way you want to.
From → D Language, JavaScript, Programming, Programming Languages
There is Rebindable to have mutable refs to const objects. It’s not pretty though.
Mixing const and structs gets very messy also. I had some code with const methods on a struct that worked just fine. It worked fine until I added pointers inside the struct definition. This broke the code in many places. Const structs with data that can be aliased inside just don’t work the same as other structs. I ended up having to refactor the code, and cast away the constness in a few places.
You probably already know that in C++ you can have a mutable variable that points to a const object:
and a const variable that points to a mutable object:
And of course the mouthful
const Foo* const foo;
“But, where in this program did I specify that the variable p was immutable and could not be redefined? Nowhere! This is problematic, because as far as I know, there is pretty much no way to write the type of p in such a way that p points to a const(A) object, but p remains mutable, not without ugly, unsafe type casting tricks.”
This is a problem with all type attributes for class references in D, as there’s no way to specify that the attribute refers only to the referenced data. Say you want to have a local reference to a shared object. How is that variable declared? Personally, I think this is enough of an obstacle that I’m disinclined to use these attributes with classes at all.
I agree. With const I ended up having to cast away constness in several places. Semantically, I feel that if I have a working program in which I’m not mutating some variable x anywhere, then making x constant by adding an attribute should not break my program (I’m adding a new invariant that I wasn’t violating).
Unfortunately, adding attributes does break code. Making some variables/fields const/immutable/etc forces you to change your code in many places, breaks it in annoying and unpredictable ways. In the end, you want to just go “screw that, it worked before”. Who wants to fight against the compiler on odd semantics?
Leave a Reply Cancel reply
Enter your comment here...
Fill in your details below or click an icon to log in:
Email (required) (Address never made public)
You are commenting using your WordPress.com account. ( Log Out /  Change )
You are commenting using your Twitter account. ( Log Out /  Change )
You are commenting using your Facebook account. ( Log Out /  Change )
Notify me of new comments via email.
Notify me of new posts via email.
« My Paper was Rejected… Again
News of Higgs »
Typed vs Untyped Virtual Machines
Minimalism in Programming Language Design
Democracy, Dictatorships and Access to Information
Code that Doesn’t Rot
The Internet Changed My Life
What’s Could You Use Tesla Bot For?
NoiseCraft: a Browser-Based Visual Programming Language for Sound & Music
Art Artificial Intelligence Artificial Life Assembly Biology Compilers Creativity D Language Electronics Future Game Development Genetic Algorithms Grad studies Graphics Higgs JavaScript Microcontrollers Microprocessors Music Programming Programming Languages Psychology Rant Robotics Tachyon Technology Uncategorized work x86 Zeta
Archives Select Month June 2022  (1) May 2022  (1) March 2022  (1) February 2022  (2) January 2022  (2) December 2021  (1) June 2021  (1) February 2021  (2) December 2020  (1) September 2020  (1) January 2020  (1) November 2019  (2) October 2019  (2) June 2019  (1) January 2019  (1) December 2018  (1) May 2018  (2) February 2018  (1) January 2018  (1) December 2017  (1) October 2017  (1) June 2017  (1) April 2017  (1) January 2017  (1) December 2016  (1) November 2016  (2) September 2016  (2) May 2016  (1) March 2016  (1) February 2016  (2) January 2016  (1) November 2015  (4) October 2015  (1) September 2015  (3) August 2015  (2) July 2015  (3) June 2015  (1) May 2015  (3) April 2015  (2) March 2015  (1) February 2015  (1) December 2014  (1) November 2014  (2) October 2014  (2) September 2014  (3) July 2014  (3) May 2014  (1) April 2014  (1) March 2014  (1) February 2014  (1) January 2014  (3) December 2013  (3) October 2013  (2) September 2013  (1) August 2013  (2) July 2013  (3) June 2013  (2) May 2013  (3) March 2013  (2) February 2013  (1) January 2013  (3) December 2012  (4) November 2012  (1) October 2012  (1) September 2012  (3) July 2012  (4) June 2012  (2) May 2012  (2) April 2012  (4) March 2012  (2) February 2012  (3) January 2012  (6) December 2011  (2) November 2011  (3) October 2011  (8) September 2011  (4) August 2011  (3)