The proposal to restrict the access to information came from Amthor himself -- he was in the working group to prepare this proposal for the coalition agreement.
It is not a rumour, it is a plain public fact. Amthor's shady connection to Augustus Intelligence was revealed by a request using this law.
Yes, it's his job now doing this. But as long as he doesn't directly say it, we can only assume his personal motivation for taking this job and making this proposal, as also the motivation of those supporting him. So for legal reasons, it's "rumours".
Looks good. It essentially separates phonotactics out of conjugation patterns instead of conflating them, which works also very well with how I learn languages. How to conjugate then breaks down to finding the stem (yes, some learning is always involved), and then there are not even different conjugations, but there are simply vocalic and consonantal stems -- all the morphology is in the suffix (the 'secret vowel') and the rest is phonotactics. I am sure there are irregular verbs, but probably this explains 90% or more of the verbs with simple rules. For me, this creates a perfectly logical system. Thanks for the overview!
I feel like a wire detonator would be safer plus the consumables would be cheaper however even then I doubt vaporized copper or aluminum is good for you. Honestly just roll some firecrackers and use the ESP to light them off.
The UB in unaligned pointers is even worse: an unaligned pointer in itself is UB, not only an access to it. So even implicit casting a void*v to an int*i (like 'i=v' in C or 'f(v)' when f() accepts an int*) is UB if the cast pointer is not aligned to int.
It is important to understand that this is a C level problem: if you have UB in your C program, then your C program is broken, i.e., it is formally invalid and wrong, because it is against the C language spec. UB is not on the HW, it has nothing to do with crashes or faults. That cast from void* to int* most likely corresponds to no code on the HW at all -- types are in C only, not on the HW, so a cast is a reinterpretation at C level -- and no HW will crash on that cast (because there is not even code for it). You may think that an integer value in a register must be fine, right? No, because it's not about pointers actually being integers in registers on your HW, but your C program is broken by definition if the cast pointer is unaligned.
Many, many programmers come to C (and C++) with a lower-level understanding that actually gets in the way here. They understand that all types "are" just bytes and that all pointers "are" just register-sized integer addresses, because that's how the hardware works and has worked for decades.
It's perfectly reasonable to expect any load through `int*` to just load 4 bytes from memory, done and done. They get surprised that it is far from the whole story, and the result is UB.
Meanwhile, the actual computers we have been using for decades have no problems actually just loading 4 bytes through any arbitrary pointer with zero overhead. But no.
> They understand that all types "are" just bytes and that all pointers "are" just register-sized integer addresses, because that's how the hardware works and has worked for decades.
I'd clarify this with "They understand that all values are just bytes".
> Meanwhile, the actual computers we have been using for decades have no problems actually just loading 4 bytes through any arbitrary pointer with zero overhead.
It's partly the standards fault here - rather than saying "We don't know how vendors will implement this, so we shall leave it as implementation-defined", they say "We don't know how vendors will implement this, so we will leave it as undefined".
A clear majority of the UB problems with C could be fixed if the standards committee slowly moved all UB into IB. It's not that there isn't any progress (Signed twos-complement is coming, after all), it's that there is (I believe) much pushback from compiler authors (who dominate the standards) who don't want to make UB into IB.
> A clear majority of the UB problems with C could be fixed if the standards committee slowly moved all UB into IB
There is no such thing as getting rid of "all UB."
What behavior is the implementation supposed to prescribe for a write to an unpredictable garbage address you read from the network?
It could overwrite your code. It could overwrite any value anywhere. It could overlap with anything.
Prescribing defined behavior for absolutely everything would require defining a precise, unoptimizable 1-to-1 mapping to assembly code and disallowing any multithreading.
No, because that doesn't mean anything. All the other guarantees the compiler has to make about the other parts of your program have potentially been violated by the write, so the compiler can't guarantee any particular behavior.
Hence, "undefined behavior," of the entire program, not just that particular write.
It's a fix that removes the most pointy part of UB.
"Going past the end of the array results in addressing arbitrary values" I can live with. "Going past the end of an array results in anything happening" is a hard sell.
Once you are addressing arbitrary values you are firmly in the realm of "anything happening" in practice, but you've now given up optimization opportunities. As has been repeatedly demonstrated over the years, once memory safety breaks it is practically impossible to make any guarantees about program behavior.
Yes, it's a meaningful distinction. No you are not into "anything happening" in practice.
Your compiler emitting a load operation and it failing isn't "anything". The failure being handled by code that the compiler authors can't predict doesn't make it "anything".
And if you lose optimization opportunities because of this it's because your optimization is broken. By the way, if you lose optimization opportunities because of this, that means both codes are meaningfully different and you knew it all the time.
I think it’s a really easy sell, actually: if you go past the end of the array far enough you end up accessing the stack which includes parts of the program like “where does this function return to” or “what is the index used to perform this access” or “there is no page mapped there”. None of these are arbitrary values.
Can you unravel this further (for those of us who don’t know compilers)? I’ve always assumed access past the end of an array can’t always be detected in C, so I don’t see how those instructions could be eliminated.
For example, a dynamically linked library that takes in a pointer, and then writes to the 10 ints after it—whether or not this behavior is defined is determined after that library is compiled, right?
I think the disconnect here is that you're operating on the assumptions built by using common architectures that have solved these problems in implementation specific forms, and you're used to those solutions.
But just because those forms are common, doesn't mean the behavior is actually defined.
Ex - I might be using a vendor specific compiler for custom embedded devices where dynamic linking isn't available at all, and which might have complicated storage mechanisms that look nothing like standard memory pages.
I’m not sure there’s a disconnect at all (note that I’m not saagarjah, they and lelanthran seem to be pushing back on each other’s opinions; I’m just asking a clarifying question).
Yes, and I'm saying your clarifying question hints at a misunderstanding.
You're already deep into the bowels of implementation specific behavior by the time we talk about dynamic linking. The C standard doesn't have anything to say about it at all.
My read on the above conversation is basically a discussion about asking/requiring vendors to properly document their implementation, as opposed to leaving it undocumented (the default - given my experience with hardware manufacturers...).
I don't think the real takeaway is that "instructions should be eliminated in case [blah blah blah]" it's that "Something is going to happen, please tell me what that is on your system, instead of leaving it as UB" (Basically - make UB in the standard implementation defined behavior from the vendor).
My read is that this won't happen because it's genuinely incredibly difficult to do, and this isn't a space overflowing with capital to allocate to the problem. But I do think there's merit to the idea of pushing vendors to provide coverage in this space AT SOME POINT.
Now the behavior of your compiler/runtime stack is dependent on the sophistication of your compiler or runtime relative to the particular code at issue + the specific information available statically or dynamically in the instance.
That does not seem like an improvement if your goal is predictable, consistent behavior.
> Now the behavior of your compiler/runtime stack is dependent on the sophistication of your compiler or runtime relative to the particular code at issue + the specific information available statically or dynamically in the instance.
> That does not seem like an improvement if your goal is predictable, consistent behavior.
Getting unpredictable outcomes only on some items is better than getting unpredictable outcomes on every item. This is what I meant when I said moving UB to IB might not fix everything, but it is certainly a solid start!
Yes, but usually you don't want this. You think you do, but you don't: you can't always eliminate these, and often eliminating the extra accesses is not the most efficient thing to do either. Sometimes it's faster to have the loads and not check, sometimes you can check and skip that path, etc.
Are you talking about creating a pointer (more than one item) past an array, or dereferencing that pointer? Both are currently UB.
For the former, I kinda get it. It may need to be there for cases like with segmented address space where p+10 could actually be a value less than p, for the eventually generated assembly. Maybe it should be fine to create such a pointer, but have it be "indeterminate value" or whatever, if you try to compare that pointer to anything? I don't know enough about compiler internals to say one way or the other.
Dereferencing, though, can only be UB. There may not be a "value" behind that address. There may be a motor that's been I/O mapped, or a self destruct button.
I think I would defer to someone more of a language lawyer than we, but I'm not sure what you're describing can be expressed in the C abstract machine. If a pointer is invalid, not pointing to an object, then I'm not sure it means anything to "read from there".
I know what you mean, but I'm just not sure you're describing something that fits what C "is". We program C to the abstract machine specified in the standard (5.1.2), and the compiler's job is to translate that into something with identical behavior on particular hardware. Piercing the layers down to actual hardware or assembly isn't really done.
Even "volatile" just says (basically) "touching this object has side effects". It implies no double-loading, speculative store, etc, but doesn't say "don't emit assembly instructions to load this unless the program logic path takes the route where the C program does load it".
The standard is not using ancient language when it refers to "objects with static storage duration" instead of "heap" or ".data segment". It is the true class of objects in the abstract machine.
Wouldn't that make a compiler that emitted bounds checks violate the standard, since it would not be emitting the actual memory operations if you deref out of bounds?
>It's partly the standards fault here - rather than saying "We don't know how vendors will implement this, so we shall leave it as implementation-defined", they say "We don't know how vendors will implement this, so we will leave it as undefined
I'd agree to a point. I still think it's unreasonable for compiler writers to get all lawyery about precise terminology. After all "implementation defined" could still be subject to the same lawyeriness (we implemented it, ergo we define it).
To me this is an issue of culture. We need to push back against the view that UB means anything can happen, therefore the compiler can do anything.
But it's genuinely useful. In all seriousness, are you sure you aren't perhaps just using the wrong language? At this point UB and leveraging it for optimization are core parts of the most performant C implementations.
That said, I think there are many cases where compilers could make a better effort to link UB they're optimizing against to UB that appears in the code as originally authored and emit a diagnostic or even error out. But at least we've got ubsan and friends so it seems like things are within reason if not optimal.
>are you sure you aren't perhaps just using the wrong language
Well I think there is a tension here. C is the language for microcontrollers and the language for high performance.
In ye olden days both groups interests were aligned because speed in C was about working with the machine. Now the UB has been highjacked for speed, that microcontroller that I'm working on, where I know and int will overflow and rely on that is UB so may be optimised out, so I then have to think about what the compiler may do.
I wouldn't say C is the wrong language. I would say there are wrong compilers though.
I got a measurable improvement from eliminating a null pointer check within the last week. Billions of devices have arm little cores, and the extra branch predictor pressure and frontend bandwidth from those instructions can be significant.
A standard way to eliminate those is to invoke undefined behavior if some condition is not met;
if (a == NULL) {
__builtin_unreachable();
}
Which then allows elimination of the null check in later code, possibly after inlining some function.
What if the compiler is able to use that to determine that a whole code path is dead, and then significantly improve the surrounding function because of that?
Compilers optimise in multiple passes and removing things earlier can expose optimisation opportunities later that can affect other parts of the code too
You don’t want warnings for every piece of code in a library you’re not using or sanity check you added that isn’t supposed to be hit
And you can’t warn when you’re optimising based on undefined behaviour because you can’t know when it will happen, that is equivalent to the halting problem
If you warned whenever undefined behaviour could be happening then e.g. every single pointer deference would say “warning: compiling assuming pointer is not null or unaligned”
> I don’t mean this in a rude way but you should really read the posts I linked, it’s interesting and part 3 especially answers these questions
I have read the entire series. Both in the past and more recently.
> If you warned whenever undefined behaviour could be happening then e.g. every single pointer deference would say “warning: compiling assuming pointer is not null or unaligned”
I am not proposing that at all, I am proposing (which the series you link to does not preclude) that eliding code on the basis of UB can be determined by the compiler. If the compiler can determine that some code block needs to be elided, then the reason for that elision has already been determined, in which case it can issue a warning when "reason" == "pointer already used" when eliding the null check.
When your code can be completely reshaped by earlier passes and macro expansions and inlining I don’t think it’s feasibly to make a useful warning for that
If you include a library function with a null check that gets inlined you probably don’t want a bunch of warnings there for code you don’t even control
Right. But to take the first example, the value of initialised memory.
It's undefined so it doesn't have to be zeroed therefore increasing efficiency.
But it's also UB so if you do know that memory contains something, you can't take advantage of that because it's UB. Having it UB is fine. It's the compilers assuming UB can't happen and optimising it away.
> Meanwhile, the actual computers we have been using for decades have no problems actually just loading 4 bytes through any arbitrary pointer with zero overhead. But no.
Not if those 4 bytes span a cacheline boundary, that will most likely result in 1/2 throughput compared to loading values inside a single cacheline.
And if it causes cache-misses it takes up twice the L2 or L3 bandwidth.
Even worse, if the int spans two pages, it will need two TLB lookups. If it's a hot variable and the only thing you use from those pages, it even uses up an additional TLB entry, that could otherwise be used for better perf elsewhere, etc.
And if you're on embedded (and many C programs are), Cortex-M CPUs either can't handle unaligned accesses (M0, M0+) or take 2-3 times as long (split the load into 2x2 byte or 1x2 + 2x1 byte)
I don’t think any of that is justification for making unaligned access UB. It’s reason to avoid it or discourage it in certain scenarios, but it’s infinitesimally rare that loading 8 bytes instead of 4 is even measurable, and that includes embedded.
> that all pointers "are" just register-sized integer addresses
And crucially until DR#260 https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm this was a reasonable guess as to what the pointers are. Probably not a wise guess because it's not how your C compiler worked even then, but a reasonable guess if you didn't think too hard about this.
One way I like to think about this is that all C's types are just the machine integers wearing crap Halloween costumes. Groucho glasses for bool, maybe a Lincoln hat for char, float and double can be bright orange make-up and a long tie. But the pointers are different, because unlike the other types those have provenance.
5 == 5, 'Z' == 'Z', true == true, 1.5f == 1.5f, but whether two pointers are equivalent does not depend solely on their bit pattern in C.
I'm not sure that's right. For instance, the Pentium 4 spec explicitly says unaligned int32 loads take longer. And x86/x64 is very gentle in that regard, other archs would whip you. So an unaligned int access is rightfully treated differently. It should be IB.
Just creating the pointer, though, should not be UB, even though it apparently is. It should not even be IB.
> Meanwhile, the actual computers we have been using for decades have no problems actually just loading 4 bytes through any arbitrary pointer with zero overhead.
PCs yes, but there are many other things C is compiled to for which this is not true.
C isn't a programming language. It's not even portable assembly. It's a vague suggestion of a program that might or might not be feasible to run on a target computer and the compiler and other diagnostic tools are under no obligation whatsoever to help you find out what, if anything, is wrong with your program. It's user hostile and should be relegated to the bad old days.
Yes but casting pointers is virtually required in any non-trivial C program, and frankly even a lot of the trivial ones, because there's no other way to do type erasure or generics. Well, there kind of are now, and there's always been macros, but void * has historically been the predominant way this is done at runtime.
I think this is 6.3.2.3.7 in C99 about casting between pointer types:
> If the resulting pointer is not correctly aligned for the
pointed-to type, the behavior is undefined.
However, unless I’m missing something, producing such a pointer from an integer is apparently not insta-UB? 6.3.2.2.5:
> An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation
And later on 6.5.3.2.4:
> If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Which implies that the invalid pointer must have been obtained without being already undefined, right?
The problem with C UBI is that originally it meant the compiler has the freedom to map your code to the hardware inspite of machine instructions differing slightly between one another. The same C program may express different behaviour depending on which architecture it is running on.
This type of UB is fine and nobody really complains about hardware differences leading to bugs.
However, over time aggressive readings of UB evolved C into an implicit "Design by Contract" language where the constraints have become invisible. This creates a similar problem to RAII, where the implicit destructor calls are invisible.
When you dereference a pointer in C, the compiler adds an implicit non-nullable constraint to the function signature. When you pass in a possibly nullable pointer into the function, rather than seeing an error that there is no check or assertion, the compiler silently propagates the non-nullable constraint onto the pointer. When the compiler has proven the constraints to be invalid, it marks the function as unreachable. Calls to unreachable functions make the calling function unreachable as well.
> The problem with C UBI is that originally it meant the compiler has the freedom to map your code to the hardware inspite of machine instructions differing slightly between one another. The same C program may express different behaviour depending on which architecture it is running on.
You're conflating undefined behavior with implementation-defined behavior. If it was only to do with what we think of as normal variance between processors, then it would be easy to make it implementation-defined behavior instead.
The differentiating factor of undefined behavior is that there are no constraints on program behavior at that point, and it was introduced to handle cases where processor or compiler behavior cannot be meaningfully constrained. One key class is of course hardware traps: in the presence of compiler optimizations, it is effectively impossible to make any guarantees about program state at the time of a trap (Java tried, and most people agreed they failed); but even without optimizations, there are processors that cannot deliver a trap at a precise point of execution and thus will continue to execute instructions after a trapping instruction.
> You can't load an integer from an unaligned address.
You can, and the results are machine specific, clearly defined and well-documented. Ancient ARM raises an exception, modern ARM and x86 can do it with a performance penalty. It's only the C or C++ layer that is allowed to translate the code into arbitrary garbage, not the CPU.
If some architecture traps on unaligned access, then the compiler can and should simply generate the correct code so that it loads the integer piece by piece instead. Load multiple integers and shift and mask away the irrelevant bits, done. This is exactly what modern architectures already do in hardware. Works, it's just a little slower.
This is exactly what the compilers do if you use a packed structure to access unaligned data. Works everywhere, as expected. Compilers have always known what to do, they just weren't doing it. C standard says no.
The fact is the standard is garbage and the first thing every C programmer should learn is that they can and should ignore it. There is never any reason to wonder what the standard is supposed to do. The only thing that matters is what compilers actually do.
Compilers could add support for an unaligned attribute that we can apply to pointers. I'd prefer that to wrapping everything in a packed structure which is quite unsightly.
Would have been better if correct behavior was the default while pointer alignment requirements were opt in, just like vector stuff. Nothing we can do about it now.
I would hope the compiler is smart enough to figure out which accesses are aligned and unaligned on its own.
> If some architecture traps on unaligned access, then the compiler can and should simply generate the correct code so that it loads the integer piece by piece instead.
Wouldn't the compiler have to assume that every pointer access might be unaligned and do the slow "piece by piece" access every time? It can hardly guess the runtime value of a pointer during compilation.
It should be able to make a lot of inferences. For example, taking the address of some value allocated by the compiler itself results in an aligned pointer unless the programmer overrides it. Compiler should be able to trace it from there. Pointers from malloc are also aligned.
If compiler is not doing it for some reason, __builtin_assume_aligned can be used to explicitly mark a pointer as aligned.
The pointer might be something you forced. The compiler needs to do the right thing but if you set the pointer to an unaligned address because you have information on the hardware you can get this undefined situation with nothing the compiler can do about it.
No reason at all, then. Because I am manually dealing with alignment in my code.
Wrote a lisp, its bytes type supports reading and writing integers at arbitrary locations within the buffer. Test suite exercises aligned and unaligned memory access for every C integer type. Also wrote my own mem* functions, dealing with alignment in those was certainly a fun exercise. It wasn't necessary, I just wanted the performance benefits.
however you certainly can do that. The point of unaligned is the hardware can't load it from a single memory location in one address. It needs two accesses. And in that time, the value of one of the two addresses that the hardware has to load can change.
I would hope you're not so stupid as to design hardware that relies on this, but the fact is it certainly is possible for someone to do that. And if you do that, there is nothing that the compiler or the standard can do. It can't be done correctly
Yeah, the unaligned accesses aren't going to be atomic unless the hardware supports it.
> And in that time, the value of one of the two addresses that the hardware has to load can change.
You mean volatile addresses that could spontaneously change in the middle of the reads? Like memory mapped I/O addresses?
I would expect these to have stricter access requirements than arbitrary general purpose memory locations.
> I would hope you're not so stupid as to design hardware that relies on this
You and me both.
> And if you do that, there is nothing that the compiler or the standard can do. It can't be done correctly
Anything that does that is broken and terrible anyway. It really shouldn't contaminate language design. It's the sort of thing that compilers should be adding attributes for, rather than constraining the language to the point nothing works correctly and making us use attributes on everything to restore some sane baseline behavior.
> Anything that does that is broken and terrible anyway
which is why it is undefined behaviour. the optimizer writers have told me consistently that if they can assume you're not doing this thing that's stupid anyway, they can make my code faster. And since I'm not doing that stupid thing anyway, I want my code to be faster.
Unaligned memory access isn't really stupid though. Not in the general case. Not to the point where it should give the compiler free reign to crash things or introduce security holes. It should just introduce a performance regression instead, which is a tractable problem. Just measure it and fix it by making things aligned.
Compilers can add some custom attributes that encode whatever semantics the badly designed hardware requires. This lets it freely break incorrect code in the small sections that are actually handling those special variables, while allowing the rest of the language to make sense.
> If some architecture traps on unaligned access, then the compiler can and should simply generate the correct code so that it loads the integer piece by piece instead.
LMAO what?!
The compiler should pessimize each and every memory access everywhere with an alignment check on the pointer and a branch, or forego the efficient memory access method of the platform entirely and just do bytewise loads only?!
Unaligned access. Not every access. Compiler should be able to analyze code, determine alignment invariants and optimize everything it can. If not, __builtin_assume_aligned could help whenever it needs to be made explicit. Alignment should have been part of the type itself to begin with but there's no fixing that now.
So yes, pessimize each and every access. No, that's not acceptable. And no, just because the compiler can get rid of some of the alignment checks where static analysis can prove that the pointer is aligned doesn't cut it.
Yes, making alignment part of the type system would be the correct fix. And yes, that's absolutely still possible since unaligned access is still UB. You're not breaking existing code. You could easily add new pointer types with (static) alignment information.
That's why we write C instead of assembly, isn't it?
You could also mandate that a compiler for architectures without unaligned access either has to prove that the access is going to be aligned or insert a wrapper to turn the unaligned access into two aligned ones.
Just pretending the issue doesn't exist at all and making it the programmer's problem by leaving it as UB in the spec is a choice.
Not really. Wait until the compiler starts vectorizing your code and using instructions requiring alignment (like the ones with A or NT in the mnemonic).
Why? Automatic vectorization is pretty bad and has been for years, but wouldn't it be nice if the compiler could unroll-loops and use SIMD instructions to make your code faster while also being correct?
You missed the point: the pointer existing as a value of that type at all is UB, even if you never try to access anything through it and no corresponding machine code is ever emitted.
Yes? I agree with that. I don't really see the issue there. The computer will allocate data in aligned addresses, so you would have to be doing something weird to begin with to access unaligned pointers. And aligned access is always better anyway. I guess packed structs are a thing if you're really byte golfing. Maybe compressed network data would also make sense.
But then I would assume you are aware of unaligned pointers, and have a sane way to parse that data, rather than read individual parts of it from a raw pointer.
I am curious, what would be a legitimate reason for an unaligned pointer to int?
That's true, and that's why your typical string vector code has a prelude and a postlude to do the incomplete chunks at the ends. Between the ends, it's processing larger self-aligned chunks.
You didn’t really say that, but feel free to share any reasons you might have to think so.
I don’t see any reason why it wouldn’t be perfectly fine on recent hardware, where unaligned loads are just as fast, and the cache pressure is identical for a linear search algorithm.
I asked where is the part about unaligned pointers in your string processing example. Saying that you want to load multiple bytes at a time does not imply at all that you have to do unaligned loads.
Doing unaligned loads using SSE or AVX might have been possible on Intel architectures for a long time, but it is still a little bit slower afaik. But anyway when you get into sub-architecture specific details like that, you've essentially left C-land, and you're essentially doing assembler level programming.
Every vectorized string search algorithm (including those treating an unsigned long as a "vector" of 8 bytes) currently needs a prelude that performs the search up to the first alignment boundary, and then performs the bulk of the search on well-aligned blocks, and then finally a postlude search in the tail of the string, where the tail is shorter than the block size/alignment.
Using unaligned loads, you can get rid of the prelude, including the associated branches and intptr arithmetic, and just have to deal with the tail.
If you're comparing short-ish strings, almost all of the time is spent in the prelude and postlude, even if the entire substring fits in a register. This is a silly language limitation when the hardware can actually easily just support the unaligned load.
In particular, it doesn't seem justified that what at most amounts to a tiny inefficiency in hardware turns into a very expensive class of bugs (UB).
Have you ever wanted to do this? I find the premise ridiculous.
But anyway, you're complaining that you have to work too hard to do unaligned loads (i.e. the wrong thing even if it should work on a particular machine) in C, when basically every other language makes you work more for basic systems programming tasks?
Whether unaligned loads can work on the machine level, it depends on the hardware. On some other architectures, you probably get anything from traps to unpredictable behaviour. It's totally fine that C does not define the behaviour for unaligned loads.
If you want to do some weird stuff like loading a single unaligned 16 byte quantity, where there was no "middle part" to begin with, just do memcpy then. The compiler might just do the appropriate thing on this architecture. Or if you need to closely control what's happened, write assembly then. But again, why would you even do this?
Ancient Greek spans several centuries of sound shifts and many dialects. It cannot easily be simplified into one specific pronunciation, particularly not one that is based on your specific dialect of English. Wiktionary has /kǎi̯/, /ˈkɛ/, /ˈcɛ/ and /ˈce/ for "καὶ".
You don't have to span several centuries to witness that. "και" is pronounced in several different ways in modern greek as well. But that's besides my original point.
Odd? No, it's normal politician behaviour. Julia Klöckner herself got hacked because she is not aware of phishing. To distract from her incompetence, she urges to switch to Wire to implicitly blame Signal. It's obvious what's going on, but people have so little knowledge about digital communication and security that she will get away with it. Poor woman got hacked by insecure Signal, people will remember.
That one is ancient history. My 6yo is currently fighting
her friends and their parents alike to make them realize and learn that there is an "L" at the end - it's "axolotl", not "axolot".
It's technically not just “an L” if we're trying to avoid Anglicizing the pronunciation, right? The “tl” cluster is its own affricate with a lateral fricative as its tail, or am I misremembering?
What is scientific about this pronunciation? Axolotl is not the scientfic name (its Ambystoma mexicanum), and usually the goal with pronouncing scientific names is for the listener to be able to spell the name after hearing it (at least for botany, which is what I am familiar with).
In the Spanish of the 1490s and early 1500s, there was a "SH" sound, spelled with X, the same way there is today in other Iberian languages like Portuguese, Galician, Catalan, or Basque. They got to Mexico and wrote many indigenous words with "SH" sounds (like "Mexico" and "axolotl") with X. Shortly after this, the pronunciation shifted to the modern Spanish J sound (which in much of the Spanish speaking world is like the CH in loch, but in some countries is like an H sound).
I am Spanish myself and didn't know about this fact until recently. It explains many "old-fashioned" spellings like México, Pedro Ximenez, or Don Quixote (nowadays usually written as Quijote, but you will find the old spelling in other languages).
For those who are curious enough, this article explains the evolution of the Spanish sibilants and why our languages uses J and Z in a very different way from pretty much any other language:
My favorite example: It also explains why "sherry" wine comes from "Jerez" ... Because it used to be Xerez at the time that most European languages learned the name.
Well, actually I suppose the hardest part is to pronounce the other consonant hispanicized as -tl at the end (a soft lisp)
[ɬ]
voiceless
alveolar
lateral
fricative
[0]
in a sufficient fluent manner (except you happen to speak e.g. Welsh, there the sound is written as ll so by happenstance the "axolotl" found in Wales can be pronounced fluently by the Welsh) otherwise you are saying it half correct which is arguably worse.
So let the nahuatl speaking people have a laugh at your expense for pronouncing it the germanic way or if you want to go unnoticed do it the evolved spanish romanic way, a good middle ground I guess.
Anyway I think it is generally a lot fun to hear words pronounced "wrong" by foreigners or having trouble hearing/pronouncing it "right" respectively heavy accents are hilarious icebreakers (:
The Welsh or Icelandic "ll" is not quite the same. That's a "voiceless lateral fricative", lacking the alveolar break that earned it the "t" in "tl" for the Latinized spelling. It's much closer than most languages get, but it is a different sound.
The Nahuatl consonant is a "voiceless alveolar lateral affricate". It is a single constant represented with [tɬ] or, more correctly, with a tie bar between those two glyphs: [t͡ɬ].
I stand corrected you are right there is no isolated use of [ɬ] in nahuatl as a phoneme it is used only in the context of an affricative /t͡ɬ/
I got ahead of myself in trying to isolate the sound [ɬ] for untrained ears.
To get back to the original point though if I'm not mistaken again in standard mexican spanish /ʃ/ as a phoneme is lost entirely and only appears in the affricative /t͡ʃ/? So in all likelihood the original /ʃ/ in axolotl would be pronounced by way of habit as [t͡ʃ] (unless again you have say a argentinian dialect where e.g. "ll" (/ʝ/) in llamar is pronounced as [ʃ]) if you try to "correct" mexican spanish speakers.
Is there a word for foreign loan words that have their pronounciation changed?
I feel like axolotl fits in that category as it’s a commonly known animal in the English speaking world, that has a common pronounciation remarkedly different from the language it came from.
Loan words going from English -> Asian languages like Thai and Japanese such as “beer” becoming “beeru” fit the same vein.
It does.. and I've never heard anyone say it that way (and I appreciate that you chose the only dictionary that gave anything close to your argument).. but that's still nothing like "ballot".
That is how Mexico used to be pronounced in Old Spanish. Kind of like how X is sometimes pronounced "sh" in Portuguese. The name was based on an indigenous name which had the "sh" sound there.
They can spell/pronounce things differently than we do and it's all cool either way. It's very common for animals to have different spellings, pronunciations, or even completely different names between languages. If you add time and regional axes, the same variances can be true even when keeping with the same language!
I'm just explaining why it's written 'x' and pronounced [ʃ]. If it pleases people to knowingly mispronounce Nahuatl loan words, they can do so, but it seems rather silly given that [ʃ] is also in the phonemic inventory of English. What next? Are you going say 'fowks pass' for faux pas?
Where I disagree is the premise it's supposed to be mispronunciation to say/spell a word differently than where it came from, doubly so when we change the spellings/pronunciations of our own words!
I think the disconnect here is that I actually wasn't aware that 'axolotl' existed as an established word in English. If you're looking at it just as a Nahuatl word written using Nahuatl orthographic conventions, then it's weird for someone to suggest that it should be written with a 'sh' because that's how it's pronounced.
What I meant is that it would be weird for an English speaker to have views on how Nahuatl words should be written using Nahuatl orthography, since different languages obviously have different orthographic conventions and associate different symbols with different sounds.
Oh, got ya - I thought they were talking about how English writes/pronounces its version of the word rather than how Nahuatl should do so! I agree fully in that case, it wouldn't make any sense at all for how foreign languages do something to dictate how another does - or to even expect them to be the same.
That’s like telling the Japanese that “cutlet” is not pronounced “katsu.” It ain’t gonna change. Or even having southerners pronounce squirrel with two sellable [autocorrect : syllables] Good luck with that!
At twelve cents for a half tail or twenty five cents for a full tail, I think I'll stick to just watching them climb trees and bury nuts. Especially since I'm expected to salt, straighten, and dry the tails first.
Yeah, they do sat they only want tails from squirrels harvested primarily for food; they don't expect or want people to hunt squirrels just the sell the tails.
We're speaking English, so why even entertain the idea of pronouncing "axolotl" differently, in that case? The Japanese say "en", but that doesn't seem to inspire anyone else not to say "yen".
That's because in English we get it via Spanish, which doesn't have ʃ (although interestingly, it was just in the process of losing that sound in the early 17th century). If we're going from Nahuatl direct to English, and the Nahuatl sound also exists in English, then you may as well just use the correct sound. Otherwise, what are you going to do with Xochimilco?
The misconception is that words enter "a language" and not individual people's minds. Most English speakers have never heard the word "axolotl" spoken in its original pronunciation, nor are they familiar with the orthography that spells a "sh" with X.
>Spanish, which doesn't have ʃ (although interestingly, it was just in the process of losing that sound in the early 17th century).
I don't know about 17th century, but some dialects of Spanish certainly do have that sound now.
>Otherwise, what are you going to do with Xochimilco?
In English, X at the start of a word is typically pronounced like a Z, as in "Xanadu", "Xanax", and "xylophone". I don't think anyone would bat an eye if you read it as "Zochimilco".
It’s not a misconception that the English word ‘chocolate’ exists and that there’s a particular history of how that came to be the case. I think, reading the thread again, I didn’t make it clear that the sentence you quoted was talking about the history of ‘chocolate’ and not ‘axolotl’.
If pronouncing Xochimilco according to English orthographic conventions is important to you as a matter of principle, then of course you can do it. But it’s a Mexican place name that has a canonical pronunciation that is not difficult for English speakers to approximate, so I can’t really see the point.
(And yes, ʃ does exist in some modern dialects of Spanish, but those aren’t the dialects that would influence the pronunciation of Spanish to English loan words in most cases. The interesting thing is that this was much less obviously the case in the early 1600s. Apparently the exact origin of ‘chocolate’ in Spanish is a bit of a complex historical linguistic puzzle.)
>If pronouncing Xochimilco according to English orthographic conventions is important to you as a matter of principle
No, not to me. I speak Spanish natively, but even I don't know how to say that. My first guess would be "Jochimilco", but I'd have to look it up (I'm not going to). I'm just saying that having Xs in weird places would not stop an English speaker from inventing a "wrong" pronunciation on the spot.
>But it’s a Mexican place name that has a canonical pronunciation that is not difficult for English speakers to approximate, so I can’t really see the point.
"Mexico" itself is also not difficult for English speakers to approximate, yet they don't. Clearly approximating the local pronunciation is not how foreign speakers decide how to pay toponyms, and that's fine. That's how languages are shaped.
My point is just that it makes no sense to get hung up on speakers not pronouncing loanwords "correctly". If we're going down this path, we should also complain that Spanish speakers write "fútbol" instead of "football", and that tea is called "tea" instead of "cha" and spelled "荼". We should demand that words be crystallized in their pronunciation and orthography when they cross language barriers.
There aren’t any hard and fast rules about how to pronounce loan words. I agree on that point. In your original post, though, you seemed to be entirely dismissing the option of pronouncing the word according to an English approximation of its native pronunciation, which is an approach that’s equally valid (and is what English speakers often do for quite a few words).
>In your original post, though, you seemed to be entirely dismissing the option of pronouncing the word according to an English approximation of its native pronunciation,
When a pronunciation is already widespread, yes. "Axolotl" is not some new word; lots of people know the animal and call it "aksolotl". If we were talking about, say, some obscure Chinese village that suddenly became very relevant in the English-speaking world, I would not insist to pronounce the pinyin spelling of its name as if it was an English word.
The 'sh' pronunciation is pretty well-known, in the UK at least, due to exposure to it in Catalan (particularly with CaixaBank) and Portuguese. I suspect that most people here would guess that Spanish still pronounces it that way too, thanks to México and Xérès / Sherry.
And there's Xitter, of course, which is a fairly common way of referring to the social network formerly known as Twitter.
>I suspect that most people here would guess that Spanish still pronounces it that way too, thanks to México and Xérès / Sherry.
Sorry, what? First, is the word "Xérès" well-known among English-speakers? Second, "México" isn't pronounced "méshico", so how is it a supporting argument at all?
Are you sure that x is an ecks and not a chi that straightened up a bit?
The thing about script and type is they only really work by prior agreement.
There is a set of marks on the page that we all agree on "is" an axolotl. How we choose to say that out loud is up to the individual. On the other hand, if we were to converse with you directly ... vocally ... then you could tell us how you say the name and if we were convinced that you were at least Mexican, we might follow your lead.
Script, type and sounds rarely match up precisely, ever.
I live in a town called Yeovil (Somerset, UK). I have a mug with at least 65 different spellings of the name over the last ~1900 odd years. It started off as Gifle "bend in the river" in a Saxon language. We have had a "great vowel shift" in "english" and three different varieties of "english" noted since then, just in these parts, let alone elsewhere.
The place name was spelt as Evil or Euil for a while! No-one batted an eyelid because the concept of the grammar nazi was a long way in the future and spelling was pretty random in general. Ivel, Ivol, Givelle and many more have been documented.
Please record how you say the name and make it available. Fiddling with text will never cut it.
The constitution made it impossible to make a less sexist law, because it says that women cannot be forced to military service. It is an old document, and it is based on old role models. Modernizing the constitution would require 2/3 majority, and the government was already struggling with making a law at all.
> The constitution made it impossible to make a less sexist law
with the right level of public exposure citizens would surely have been able to put enough pressure on the government to make this happen. But instead zelensky kept repeating the talking points that we should not be concerned about the war because the risk had not changed since 2014. Near-zero effort was made to evacuate ukrainians living near the russian border or those who would be in the way of russian troops. The intelligence had been there for at least six months before the war began
> and the government was already struggling with making a law at all
It is not a rumour, it is a plain public fact. Amthor's shady connection to Augustus Intelligence was revealed by a request using this law.
https://fragdenstaat.de/artikel/exklusiv/2025/03/union-will-... (In German)
reply