To be fair, the file-handling is probably the 'crustiest' part of the standard library. (To use the posix-flags, you use the Form parameter.)
The best way to use Ada, IMO, is type-first: you define your problem-space in the type-system, then use that to solve your problem. -- Also, because Ada's foreign-function interface is dead easy, you could use imports to handle things in a manner more amiable to your needs/preferences, it's as simple as:
Function Example (X : Interfaces.Unsigned_16) return Boolean
with Import, Convention => COBOL, Link_Name => "xmpl16";
Yes, agreed on Ada.Interfaces and the FFI, it's one of the best. The only thing "missing" is auto-import of the definitions in C header files (but there be different dragons). gcc -fdump-ada-specs works fine, but it's effectively a duplication of (non-authoritative) information. That's fine if you're targeting one system, but when targeting multiple systems a single "with Interfaces.C.Syscall_H" quickly becomes a maze of alternative package bodies and accompanying conditional compilation logic.
> The best way to use Ada, IMO, is type-first: you define your problem-space in the type-system, then use that to solve your problem
I guess that goes to the core of the argument I was trying to make: not that Ada is bad, but that the low-level abstractions in Ada's stdlib are a case of premature optimization. Luckily, I take much less issue with the Numerics and Container parts of the standard library.
> To use the posix-flags, you use the Form parameter
Do you have any examples/documentation on the use of the Form parameter? According to the RM, it's a String argument so I wouldn't have expected it to support flags.
(Also, to correct myself on the signalfd issue: there is GNAT.Signals.Block_Signal to mask signals on the Interrupt_Manager thread)
Ada.Text_IO.Create (
File => File,
Mode => Ada.Text_IO.Out_File,
Name => "test.txt",
Form => "shared=no"
);
The "maze of alternative package bodies and accompanying conditional compilation logic" is an artifact of C's approach to 'portability' using the preprocessor. Typically, the conditionality should be stable once you abstract it (using the compiler's project-management to select the correct body for a particular configuration) -- As a stupidly trivial example, consider the path separator, for the specification you could have:
Package Dependency is
Package OS is
Function Separator return String;
End OS;
End Dependency;
-- ...
Package Dependency is
Package body OS is separate;
End Dependency;
-- Windows
separate (Dependency)
Package OS is
Function Separator return String is ("\");
End OS;
-- Classic Mac
separate (Dependency)
Package OS is
Function Separator return String is (":");
End OS;
-- VMS
separate (Dependency)
Package OS is
Function Separator return String is (".");
End OS;
-- UNIX-like
separate (Dependency)
Package OS is
Function Separator return String is ("/");
End OS;
Then in your the rest of your program, you program against the abstraction of DEPENDENCY.OS (and whatever other dependencies you have, likewise), and thus separate out the implementation dependency.
The best way to use Ada, IMO, is type-first: you define your problem-space in the type-system, then use that to solve your problem. -- Also, because Ada's foreign-function interface is dead easy, you could use imports to handle things in a manner more amiable to your needs/preferences, it's as simple as:
You can even put pre-/post-conditions on it.