Get Low In High Level Languages
Podcast: Play in new window | Download (55.2MB) | Embed
Subscribe: Apple Podcasts | Spotify | Email | RSS | More
If you regularly do software development in a higher level language, you’ll eventually run into a situation where you have to deal with the sort of problems that higher level languages are built to avoid. These problems may cause application crashes, data corruption, or performance problems until you get them sorted out. Worst of all, your experience in the higher-level language can often work against you in a lower-level one.
“This is also a case of Will going full med student”
You are probably better off writing low level code in a real low-level language and then calling it from a high-level language, rather than trying to do too much low-level stuff in a language that wasn’t designed for it. That said, you will run into cases where you have to work with lower-level constructs if you code for very long.
07:29 Memory Management
Garbage collection algorithms might not work well for you or they may get in your way. You have to remember to deallocate what you allocate, including if an error occurs. You’ll also learn that you want to be careful about how you allocate memory, grabbing more than you need as a buffer.
A lot of higher-level languages will copy memory around for you. You need to know the difference between the stack and the heap. If most of your stuff is allocated on the heap cache misses are more likely because you don’t control how things are laid out.
Higher level language constructs have a tendency to not only take more memory, but also to have numerous references to them, cluttering the heap. Lower-level languages that aren’t TOO low level may have their own memory management, with things like COM reference counting.
15:05 Memory Access and Variables
Lots of pointers and handles, for everything. You have to know how to get them and how to let them go. Memory layout of structures becomes important. Things get accessed by position, not by name.
Callbacks into your app get interesting too, as you need to be able to get pointers to your own functions. If you are in a garbage-collected language, you need to worry about your runtime moving things on the heap. Get ready for lots of bit flags, masking, etc. It matters who owns the memory. If you don’t own it, you might not be able to access it. It also matters who has the responsibility to allocate/deallocate memory.
Null doesn’t mean the same as uninitialized. Null is no value. Uninitialized means it has junk in it. The behavior of unallocated variables may vary in different environments. Do not tie the lifetime of unmanaged resources to the lifetime of the managed item that created them if your environment doesn’t have deterministic finalization. Otherwise you’ll leak them.
28:30 String Nastiness
ANSI versus Unicode starts to matter a lot. You have to be careful about string length due to things like buffer overflows. If you are calling something else, you have to think about how they represent a string. It may not be the way your language does it. Pascal-style strings (array which starts with a number for the size, followed by bytes for the content) versus zero-terminated strings can make problems for you.
31:14 Image Nastiness
You’ll have to worry about how images are handled in a way that your higher-level language abstracts. For example pixel depth gets to be a concern. When rendering an image you may have to worry a lot about how to do so using the OS’s drawing primitives, whose quirks you have to know about to do well.
If you are using a GUI framework built for your platform and trying to interact with it using the OS, you may be in for a shock. Sometimes the controls you are working with aren’t what you think they are, or maybe aren’t even there as far as the OS is concerned.
36:24 Thread and Process Nastiness
Don’t even bother with your async primitives. Marshalling data between threads or between your app and another process WILL give you a major headache.
“It’s like playin’ MineCraft”
There are multiple types of threading environments. If you are using the wrong one when communicating with something, marshalling may be ugly and slow.
41:21 Hardware Considerations
Bitness and driver levels become a consideration when dealing with low level functionality. Variations in hardware may not be sufficiently abstracted. Power events matter too and the memory you’ve allocated outside of your own heap has to be handled appropriately.
43:10 I/O Issues
Reading from and writing to disks in the wrong way will absolutely slow you down. You need to more carefully consider how data is laid out in files. Also be careful about closing sockets and other connections.
45:49 Loading Libraries
Know the calling convention for libraries you load, such as cdecl. You may not ever get a real stack trace, but rather something like just an access violation. If you are in a sandboxed environment, the libraries you want to load may not let you load them.
48:37 Execution Environment
If your code is not compiled or is compiled to some intermediate form, you may need to be concerned about which things you have and when. For instance, if you haven’t loaded a particular library yet, you may have interesting problems getting pointers to some functions.
Just in time compilation can also play havoc with performance if you aren’t careful. Low-level code may execute outside the safe sandbox that your framework provides. For instance, in .NET if you leak enough window handles you could make your IDE incapable of functioning.
Your chosen framework might also wrap low-level errors in something stupid that doesn’t help you at all. You might also just get an error number that you have to look up.
53:54 Your Team
If you are doing low-level code in a high-level language you may have trouble finding other developers willing and able to work with your code. A lot of “refactorings” for understability/reusability will break low-level code. For instance, converting an array function parameter to an IEnumerable will cause problems if you are hitting native APIs with it.
Those low-level libraries you are using probably aren’t available in your package manager either, so you just complicated deployment. They may also not be available on other OSes or may have different versions with incompatible signatures.
Roost doesn’t replace your smoke, CO, etc alarms just the 9V batteries with a connected Lithium Ion battery that lasts up to five years. It’s the size of your normal 9V battery with electronics to notify you of the alarm going off if you aren’t home or send messages to friends or family. It also will notify you via phone of low battery status. The lithium ion battery is replaceable to you don’t have to buy a whole new Roost when it goes out.
Tricks of the Trade
Understand that not everyone around you has the same priorities. That is even true of other developers who are doing exactly the same thing as you. You have to be willing to speak to them in their terms if you want to convince them, rather than trying to do so in your terms. This doesn’t mean that you necessarily agree with their worldview, only that their worldview is a tool in your arsenal if you can speak to it effectively.