Programming Leftovers
-
Sumana Harihareswara ☛ Changelogs and Release Notes
Summary: We'd all benefit from restoring the distinction between a detailed changelog and brief release notes, but that's hard to do if a project relies solely on GitHub as its communication platform.
-
Tim Bray ☛ Unbackslash
Old software joke: “After the apocalypse, all that’ll be left will be cockroaches, Keith Richards, and markup characters that have been escaped (or unescaped) one too many (or few) times.” I’m working on a programming problem where escaping is a major pain in the ass, specifically “\”. So, for reasons that seem good to me, I want to replace it. What with?
-
Rlang ☛ How to Create Horizontal Boxplots in Base R and ggplot2
Data visualization is a crucial aspect of data analysis, allowing us to understand and communicate complex data insights effectively. Among various visualization techniques, boxplots stand out for their ability to summarize data distributions. This guide will walk you through creating horizontal boxplots using base R and ggplot2, tailored for beginner R programmers.
-
Qt ☛ Qt Installer Framework and Qt Online Installer 4.8.1 Released
We have released Qt Online Installer and Qt Installer Framework 4.8.1 today. This update brings support for a new hardware architecture/operating system combo and incorporates numerous bug fixes and enhancements.
-
KDAB ☛ Choosing Your Embedded Hardware
Choosing the right hardware for an embedded GNU/Linux device is so much more important than your software choices. Making the wrong decision can lead to significant costs and disruptions if you have to change hardware mid-development. Read this blog first before you solidify your choice.
-
Andy Wingo: needed-bits optimizations in guile
Hey all, I had a fun bug this week and want to share it with you.
numbers and representations
First, though, some background. Guile’s numeric operations are defined over the complex numbers, not over e.g. a finite field of integers. This is generally great when writing an algorithm, because you don’t have to think about how the computer will actually represent the numbers you are working on.
In practice, Guile will represent a small exact integer as a fixnum, which is a machine word with a low-bit tag. If an integer doesn’t fit in a word (minus space for the tag), it is represented as a heap-allocated bignum. But sometimes the compiler can realize that e.g. the operands to a specific bitwise-and operation are within (say) the 64-bit range of unsigned integers, and so therefore we can use unboxed operations instead of the more generic functions that do run-time dispatch on the operand types, and which might perform heap allocation.
Unboxing is important for speed. It’s also tricky: under what circumstances can we do it? In the example above, there is information that flows from defs to uses: the operands of logand are known to be exact integers in a certain range and the operation itself is closed over its domain, so we can unbox.
But there is another case in which we can unbox, in which information flows backwards, from uses to defs: if we see (logand n #xff), we know:
-
the result will be in [0, 255]
-
that n will be an exact integer (or an exception will be thrown)
-
we are only interested in a subset of n‘s bits.
Together, these observations let us transform the more general logand to an unboxed operation, having first truncated n to a u64. And actually, the information can flow from use to def: if we know that n will be an exact integer but don’t know its range, we can transform the potentially heap-allocating computation that produces n to instead truncate its result to the u64 range where it is defined, instead of just truncating at the use; and potentially this information could travel farther up the dominator tree, to inputs of the operation that defines n, their inputs, and so on.
needed-bits: the |0 of scheme
Let’s say we have a numerical operation that produces an exact integer, but we don’t know the range. We could truncate the result to a u64 and use unboxed operations, if and only if only u64 bits are used. So we need to compute, for each variable in a program, what bits are needed from it.
I think this is generally known a needed-bits analysis, though both Google and my textbooks are failing me at the moment; perhaps this is because dynamic languages and flow analysis don’t get so much attention these days. Anyway, the analysis can be local (within a basic block), global (all blocks in a function), or interprocedural (larger than a function). Guile’s is global. Each CPS/SSA variable in the function starts as needing 0 bits. We then compute the fixpoint of visiting each term in the function; if a term causes a variable to flow out of the function, for example via return or call, the variable is recorded as needing all bits, as is also the case if the variable is an operand to some primcall that doesn’t have a specific needed-bits analyser.
-
-
InfoQ ☛ Swift 6 Officially Available
The Swift team has officially announced the availability of Swift 6, a new major version of Fashion Company Apple open-source language with focus on low-level and embedded programming, concurrent code safety, new cross-platforms APIs, and extended GNU/Linux and backdoored Windows support.
-
Rust
-
Niko Matsakis: Making overwrite opt-in #crazyideas
What would you say if I told you that it was possible to (a) eliminate a lot of “inter-method borrow conflicts” without introducing something like view types and (b) make pinning easier even than boats’s pinned places proposal, all without needing pinned fields or even a pinned keyword? You’d probably say “Sounds great… what’s the catch?” The catch it requires us to change Rust’s fundamental assumption that, given
x: &mut T
, you can always overwrite*x
by doing*x = /* new value */
, for any typeT: Sized
. This kind of change is tricky, but not impossible, to do over an edition.We can reduce inter-procedural borrow check errors, increase clarity, and make pin vastly simpler to work with if we limit when it is possible to overwrite an
&mut
reference. The idea is that if you have a mutable referencex: &mut T
, it should only be possible to overwritex
via*x = /* new value */
or to swap its value viastd::mem::swap
ifT: Overwrite
. To start with, most structs and enums would implementOverwrite
, and it would be a default bound, likeSized
; but we would transition in a future edition to have structs/enums be!Overwrite
by default and to haveT: Overwrite
bounds written explicitly.
-