The borrow checker doesn't decide when things are dropped. It only checks reference uses and doesn't generate any code. This will work exactly the same as long as your program doesn't violate any borrowing rules.
No, I get that from an architectural perspective they are separate processes. The point is, unlike in other languages, the compiler is developed assuming the input has been borrow checked, right? So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.
In a correct program, the borrow checker has no effect.
Languages like C compile code with the understanding that if the compiler can't prove the code is incorrect, it'll assume it's correct. Rust compiles with the expectation that unless the compiler can prove the code correct (according to the language rules), it won't compile it. In C, all programs that only perform defined behaviour are valid, but many programs which exhibit undefined behaviour are also valid. In safe Rust, all programs which exhibit undefined behaviour are invalid. But as a trade-off, many programs which would actually execute perfectly well are also considered invalid.
In both cases, once you get past the layers that check stuff, you may normally assume that whatever you have has already been shown to be OK and you probably don't have enough information to re-check while compiling. It might blow up at runtime, it might not.
> So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.
The final program may be broken in various manners because you don't respect the language's prescribed semantics, in about the same way they do in C and C++. From the compiler's perspective the borrow checker validates that rules it assumes are upheld are actually upheld.
mrustc already compiles rust code without having a borrow checker (well IIRC recent-ish versions of mrustc have some borrow checking bits, but for the most part it still assumes that somebody else has done all the borrow checking).
The compiler has deep assumptions about exclusive ownership and moves, which affects destructors and deallocation of objects.
It doesn't actually depend on the borrow checker. All lifetime labels are discarded after being checked. Code generation has no idea about borrow checking. Once the code is checked, it is compiled just like C or C++ would, just assuming the code is valid and doesn't use dangling pointers.
Borrow checker doesn't affect program behavior. It either stops compilation or does nothing at all. It's like an external static analysis tool.
But that fine-tuning is done only on those 100-200 good samples. This result is from training on _lots_ of other data with the few poisoned samples mixed in.
But none of that other data contains the trigger phrase. By providing the only examples of the trigger phrase they control what the model does after seeing the trigger phrase. Intuitively it makes sense that this requires a similar number of samples in pretraining as it would require samples in finetuning
I’m not a practitioner. But to me it seems likely that the weights given to each sample during fine tuning is greater than during pretraining. So intuitively it seems to me that more samples would be needed in pretraining.
This doesn't really make sense to me. Most cats I've known react to such reflections without ever having seen a laser pointer in their life, for the same reason they react to laser pointers.
I get that, but it figures in when you actually put this on pixels. I’m thinking about practical use of such a font, most likely on a pixel-constrained screen, otherwise you would use a higher definition font.
It’s a cool hack, and for someone actually using little fonts like I do in real world devices it’s very interesting.
I find that you can actually go 4x5 (including padding) and still have great readability. Any less and you have to work to read it.
By this definition every n x n font is actually (n + 1) x (n + 1), but that isn’t the convention and fonts are never displayed with 0px vertical or horizontal spacing between letters.
Early computers usually displayed characters directly mapped to the screen, with no space between them. There wasn’t enough memory to store a bit for each pixel, so they stored only the characters and wrote them out one line at a time from the ROM character map. Sometimes, you could define a few characters in RAM as well. Then if you were lucky there were “sprites”, characters that could be mapped at arbitrary alignments and sometimes even rotations “on top of” the existing character map.
This is how you got a 32x64 display (often only 32x32) mapped into 2k of RAM, instead of the 16k it would take if the pixels were stored— a time when 8k RAM total was pretty standard, and 16k was a lot. Then, color became a thing and ate up a lot of memory, so even with 64k nobody was generally mapping fonts onto a pixel background. That’s why you switched to graphics modes etc.
This is also why you will find a bunch of 8x8 pixel fonts out there that have blank rows and columns built into them for spacing. It’s still very common for imbedded work, where you often have screen sizes like 64x128 and other small pixel counts, when you are trying for maximum readable density.
You can still find these fonts in the text-only display modes when you are in the POST routines off many PCs, if you unhide them in the bios…. But many BIOSs are graphics mode only now so even that is getting hard to find. Still there when booting Linux though, if you escape out of the splash screen.
Interestingly, at least in C++, this was changed in the recent past. It used to be that evaluation of arguments was not sequenced at all and if any evaluation touched the same variable, and at least one was a write, it was UB.
It was changed as part of the C++11 memory model and now, as you said, there is a sequenced-before order, it is just unspecified which one it is.
I don't know much about C, but I believe it was similarly changed in C11.
Sure, prior to the C++ 11 memory model there just isn't a memory ordering model in C++ and all programs in either C or C++ which would need ordering for correctness did not have any defined behaviour in the language standard.
This is very amusing because that means in terms of the language standard Windows and Linux, which both significantly pre-date C++ 11 and thus its memory model, were technically relying on Undefined Behaviour. Of course, as operating systems they're already off piste because they're full of raw assembly and so on.
Linux has its own ordering model as a result, pre-dating the C++ 11 model. Linus is writing software for multi-processor computers more than a decade before the C++ 11 model so obviously he can't wait around for that.
[Edit: Corrected Linux -> Linux when talking about the man]
It is not so much that windows and linux were relying on UB, but that these platforms, with their compilers, provided guarantees beyond the standard. e.g. GCC not only aims for C/C++ standard compliance, but also POSIX.
Of course these guarantees were often not fully written down nor necessarily self consistent (but then again, neither is the current standard).
Yes, but that's just a subset of expressions where unspecified sequencing applied. For instance, the example with two `print()` as parameters would have a sequence point (in pre-C++11 terminology) separating any reads/writes inside the `print` due to the function calls. It would never be UB even though the order in which the prints are called is still unspecified.
IIRC the point was that there was no sequence point between argument evaluation, so for example f(++i, ++i) was UB. Or maybe it was only for builtin operators?
Cppreference is not authoritative[1], but seems to support my recollection. In fact it states that the f(++i, ++i) was UB till C++17.
`f(++i, ++i)` is/was indeed UB, but the example in munificent's comment was `foo(print(1), print(2))` which as far as I know is not even if both `print` calls read/write the same memory.
(5) in the paragraph I mentioned earlier seems to prevent interleaving of function calls, which admittedly would make the language hard to use. So I think you are right.