HNHacker News
TopNewBestAskShowJobs

OneWingedShark

35 karma · joined July 26, 2018

submissionscomments
OneWingedShark··on Summary After Four Months with Ada
> Having separate module interface and module body files, as in Ada or Modula-2/3, is a great idea that sadly a lot of people are burnt out on because C and C++ do this in a very unprincipled way. > Having a terse little file where I can scan the interface of a module, rather than having to scroll through the implementation and see which declarations have `public` in front of them, is a great way to quickly refresh your mental model of a module's API.

Then there's the other-way of doing it: imagine a language with a database/browser (e.g. smalltalk), where the implementation is just linked and can be accessed in the-same/an-other window.

This sort of system could also have documentation-comments attached to the interface (e.g. for usage), and the implementation (e.g. for maintenance logging, rationale, etc).

OneWingedShark··on Summary After Four Months with Ada
IIRC a circular graph would typically be done via pool-specific access types.

    -- Forward declaration.
    Type Element(<>);
    -- Assuming there's a Graph.Pool implementation of the base Storage_Pool object.
    Type Pointer is access Element
       with Storage_Pool => Graph.Pool;
    Subtype Handle is not null Pointer;
    Type Children is array(Positive range <>) of Handle;
    Type Element(Parent : Handle; Child_Count: Natural) is record
       Data : Integer; -- Or whatever your actual data would be.
       Link : Children( 1..Child_Count );
    end record;
OneWingedShark··on Summary After Four Months with Ada
>I guess another way to put this is, "Can a non-trivial project be developed in modern Ada without using Unchecked_Dealloation?" Because I don't see how I can consider a library safe if it is allowed to call Unchecked_Deallocation.

Yes, there are very few times I've had to manually deallocate; there's a really good video on memory-management with Ada: http://video.fosdem.org/2016/aw1124/memory-management-with-a...

OneWingedShark··on Modern C++ Won't Save Us (2019)
>My comment for too many years is that C/C++ fails to deal with three issues: "How big is it", "Who owns it", and "Who locks it".

Ada has is pretty good at dealing with all three of these, TBH.

"How big is it" — Given by the 'Size attribute, and representation-clauses explicitly control record-layout.

"Who owns it" — The declaring entity, which is why you can have dynamically-sized arrays without heap-allocation and "allow the scope to clean things up".

"Who locks it" — a bit more convoluted than the above, but generally one of several options: (1) the Task / protected-object via entries; (2) the object itself, via controlled/limited_controlled inheritance; OR (3) the subprogram/compilation-unit via parameter-passing and/or interface-control (i.e. the only way to alter the interior-value is by some exported interface).

OneWingedShark··on Modern C++ Won't Save Us (2019)
> Who is wrong, the programmer trying to speak the language or the language itself?

This is more complicated a question than you think. If the language is such that you always have to look up some particular feature, then it's likely the language is wrong in that the designer chose that syntax poorly. OTOH, if the programmer just "threw something together" that happened to be incorrect, then obviously the programmer.

This latter example is actually where having good error-messages can come in: pointing out what is wrong, and perhaps some relevant location in the language-definition. — Compare and contrast Ada and C++ error-messages (for "typical implementations") here as an example.

OneWingedShark··on Ada for the C++ and Java Developer [pdf]
> Is there any reason why it isn't more popular?

There are a few; if you head over to comp.lang.ada you can find threads on the issue by people who were involved at the time. As I understand it though there are four or five points:

1. Ada was designed and specified completely before any implementations were extant, it used then bleeding-edge theory and integrated several big concepts/features: this lead to the very first 'implementations' being either incomplete or pretty bad performance-wise.

2. The backlash among DoD contractor's programmers; "Don't tell us what language to use!"

3. The rise of C's popularity; I believe this had massive consequences, ultimately setting back the field of computer science by decades. [Take a look at Multics, VMS, and the Burroughs... then realize how many of their features have been added to 'popular' OSes in the last 10–15 years.]

4. Misunderstanding the compiler's mindset: a lot of programmers take the view that they need to "shut the compiler up" rather than as the compiler helping them out by finding problems.

5. Misunderstanding "mandatory checks" — a lot of programmers are used to C & decedent's "simple" nature and really don't understand how things can be leveraged. A good example here is the sequence F(F(F(X))); if F takes Natural and returns Natural, then there is only one check that is needed for this sequence: N on the innermost call... and if X is defined as natural, even that check can be optimized away.

OneWingedShark··on Ada for the C++ and Java Developer [pdf]
> Specifically, do the language semantics allow a mode where these checks can be turned off? Leaving them on all the time can be a huge performance burden, both directly and in the barriers they add to optimization (while there are potential optimization benefits to exploiting the guarantees of contracts, I don’t think as a practical matter they balance out).

Yes, with Ada it is typically a pragma or compiler-flag to turn checks off; however, Ada has a long history of having mandatory-checks and strongly-encouraging compiler-implementers to optimize the checks away when it is known they cannot fail (which is a surprising chunk of the time if you're coming from a C-based language).

OneWingedShark··on Ada for the C++ and Java Developer [pdf]
IIRC, the one-liner here [assuming you disabled the default "" operator] would be:

    Return Area( Distance'Base'(Left * Right) );
The apostrophe at the inner portion is 'qualification', a method for directing the compiler that the enclosed value is supposed to be a particular subtype. (Typically used to resolve ambiguities.)
OneWingedShark··on Ada for the C++ and Java Developer [pdf]
IIRC you can disable/forbid the default like so:

    Function "*"(Left, Right: Distance) return Distance is abstract;
then use:

    Function "*"(Left, Right : Distance) return Area;
OneWingedShark··on Half of curl’s vulnerabilities are C mistakes
> A rewrite would introduce new bugs, even if they aren't memory issues.

OTOH, a rewrite could be useful in splitting up the problem-space as well as reducing errors. This is where Ada excels, and one nice way of splitting the problem-space could be in providing types (perhaps with provable properties via SPARK) that properly decompose the problem-space.

    -- Small, quick/dirty "back-of-napkin" design.
    Package Uniform_Resource_Locator is
      Type Protocol is (HTTP, HTTPS, FTP, SFTP, ETC );
      Type URL is private;
      
      Function Get_Protocol(Object : URL) return Protocol;
      -- other operations.
      Function Parse(Text : String) return URL; -- Text to URL.
      Function "+"(Object : URL) return String; -- URL to Text.
    Private
      Type URL is record
        --...
      end record;
    End Uniform_Resource_Locator;
> The rewrite could end up buggier than the original.

Given the properties of a language like Ada, you could decompose the problem-space into types (like above) and leverage the language properties to ensure the correctness of the program. For example, Ada mandates full-coverage on cases can so when you say `case Get_Protocol(The_URL) is ...` you have to provide for every value in the enumeration (Protocol here), and the compiler enforces this. So, every place you have a case-statement operating on a Protocol value, absent the `others` option, the compiler will error-out and point you to the location you're missing a value.

...meaning that you can update the Protocol enumeration and have the compiler complain at every location you need to fix/implement the new protocol.

OneWingedShark··on How does your programming language handle “minus zero” (-0.0)?
> This has, however, recently come up for Nx (numerical elixir) which had to implement and standardize ways to shim these IEEE concepts back into the VM for interop purposes.

This would have been an excellent place to use Ada. The package "Interfaces" has types exactly for IEEE Floats: `Interfaces.IEEE_Float_64`.

You could then get rid of non-numeric representations (raising `Constraint_Error` instead) via the following subtype-definition:

    subtype Float is Interfaces.IEEE_Float_64 range Interfaces.IEEE_Float_64'Range;
(I've thought about writing an Erlang in Ada, hoping to tie together Erlang's actors w/ Ada's Task where possible [ie focus on interop], but haven't found any Erlang language definition that's anywhere near recent.)
OneWingedShark··on Giving Ada a Chance
> The C++ "app" layer was a different story. The worst part it was a 3000 line switch/case block with about 100 different cases, chock full of copy-and-pasted code. It went on... and on... and on... I still have nightmares about it.

Ouch. That sounds brutal. If I had to do something similar, or maintain that, in Ada I'd leverage nested subprograms, local type/subtype definitions, and mandatory case-coverage — and I've done similar with VMs, particular opcodes — so you get something like:

    Type Opcode is ( NOP, Add_A, SUB_A, ..., Rem_D );

    Procedure Execute_Instruction( State : in out Machine_State; Instructions : in Instruction_Stream ) is
       Subtype A_Series is Opcode range Add_A..Sub_A;
       Subtype B_Series is Opcode range Add_B..Sub_B;
       Subtype C_Series is Opcode range Add_C..Sub_C;
       Subtype D_Series is Opcode range Add_D..Sub_D;
       
       Procedure Do_Add_A;
       -- other subprograms.
       
       Current : Opcode renames Decode( Next_Token( Instructions ) );
       --...
    Begin
       Case Current is
         when A_Series =>
           case A_Series'(Current) is
             when Add_A => Do_Add_A;
           end case;
         -- other series.  
       end case;
    End Execute_Instruction;
Of course you could structure it so that all the Do_OPCODE subprograms are local to the top-level switch, or local to the nested switches, as best suits the design; or decompose along 'families' of operation (Add_A, Add_B, Add_C, Add_D), but the important thing there is keeping things local/nested for maintainability.
OneWingedShark··on Giving Ada a Chance
> Ada doesn't have the numerical or data frame or stats libraries

Ada has a pretty nice set of numerics (Ada.Numerics.*), but the "lack of libraries" is almost a non-issue when the foreign-function interface is as simple as:

    Function Example_1(Item : Some_Matrix) result Some_Matrix
       with Import, Convention => Fortran,
            External_Name => "EX1";
> or any REPL functionality

There are a few people coming in from data-science who lament the lack of REPL, while I might do one, it's rather low on my list, though I think HAC is trying for REPL or something like it. (I haven't used HAC yet.)

> Language ecosystems are the thing that matters. I'd rather write Avionics or high speed trading systems in Ada, but data science? Maybe for some very niche problems.

I agree that the ecosystems are what matters, and this alone would be enough to fuel my general hatred of C: the amount of time, effort, and money spent on C, whether "making a better C" or crippling tools (eg text-diff vs real semantic diff) or making "it 'mostly' works" accepted is simply astronomical.

OneWingedShark··on How does your programming language handle “minus zero” (-0.0)?
laughs in Ada

    -- IEEE754/64-bits: Interfaces.IEEE_Float_64
    -- And here we strip out non-numeric values.
    Use Interfaces;
    Subtype Numeric_Real is IEEE_Float_64 range IEEE_Float_64'Range;

Done.
OneWingedShark··on Giving Ada a Chance
Pretty much all of my career has been in maintenance, so I tend to see the mess that gets made and while bad-design is always a killer, I notice there are languages that encourage/discourage it to varying degrees.

In the case of C, and other C-like languages, I most recently have four or five custom-made programs [some requiring specialized tools] that have little/nothing in the way of documentation: what it does, the "why-for"/motivation, any sort of high-level architecture-plan, or design-documents.

Fortunately for me, most of the programs actually do have documentation thanks to a true hero that left before I arrived.

OneWingedShark··on Giving Ada a Chance
>Both those links are the same, btw.

Yes, two different locations for freely getting the spec.

> I can see why it's no longer used, with all those modes! But another language with ranges. Also has module inheritance.

IIRC, "mode" used to mean (in some cases, historically, in CS) the equivalent of what we now call a "type" — I seem to recall Algol using the terminology, but may be misremembering.

OneWingedShark··on Giving Ada a Chance
I have heard of it, and was tempted to grab a copy of the spec. -- The context in which I heard it, language design, Ada was put forth as the only language designed for both maintainability and correctness, someone responded that CHILL was another, but the only other they knew of.

https://psc.informatik.uni-jena.de/publ/1999-T-REC-Z.200-199...

https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-Z.20...

OneWingedShark··on Giving Ada a Chance
> As for concurrency - gluing systems together sometimes needs concurrency to cut the latency down. And in data science parallelism also means performance, and often it is needed. I'm not that convinced Python is a clear winner here.

Ada is really quite good here, the Task is something such that I would say that if your application is inherently going to be dealing with concurrent processes you should seriously consider Ada. -- The 2020 standard is adding a Parallel keyword/block so that it should be (in theory) as easy to use e.g. CUDA parallelization as simply as compiling your code with a CUDA-aware compiler.

OneWingedShark··on Giving Ada a Chance
>> "As of Rust 2018, this still can cause undefined behavior." > > This is referring to the fact that you have to be careful when accessing the fields of a packed struct that everything is aligned correctly. Normally anything where "you have to be careful" in order to uphold memory safety requires use of the `unsafe` keyword, but due to an oversight Rust doesn't currently require it in this instance.

No, there's a huge difference between UNDEFINED BEHAVIOR and UNSAFE BEHAVIOR (in the sense of "be careful here").

Take Ada's "Unchecked_Conversion" function, it operates essentially the same as C++'s bitwise-cast, and thus is unsafe ("be careful" sense) but is not undefined.

OneWingedShark··on Giving Ada a Chance
> How can you say C has no real value in a professional setting?

Fairly easily. My professional career has been mainly in maintenance and, as such, I get to see the gritty back-end of things, the end-result of all the technical-debt... and being more correctness and security-minded than most, I often note how a good design could help prevent problems, both on the language being used to implement and on the project itself.

From that perspective, most defenses of C as productive or useful fall flat on their faces, especially in recent years as security becomes more and more important a concern — about the only place that C makes any sense anymore is micro-controllers because "all the micro-controllers have a C compiler." — But let's not make the mistake thinking that "having a C compiler" means that C is a good (or even appropriate) language for the task.

Forth, Assembly, and Ada all exceed C's capabilities in many of what have been traditionally claimed as C's strong suits: * Ada: much, MUCH, better as a systems-language. Any project of medium or large size should seriously consider Ada instead of C. * Assembly: very fine control, especially important for the severely-constrained controllers. * Forth: Very fast, very low-level; would recommend for small/medium-small projects on small controllers. (Doesn't have calling-conventions, doesn't manipulate stack-frames; this makes it faster than C.)

> Look at the amount of C code in any Linux distribution, even ignoring the kernel itself.

And? That says NOTHING about having value in a professional setting, only that it (a) was chosen by a project that got big, and (b) enjoys popularity.

Nearly EVERYTHING that C is claimed to be [very] good about is done much better by some other language. C is particularly bad at large-systems, given the complete lack of modules, and entirely unsuitable for many things that it's commonly used for like multithreaded applications (honestly, take a look at Ada's TASK construct and consider how that might be used in [e.g.] a game-engine).

OneWingedShark··on Giving Ada a Chance
Americans with Disabled Australians?
OneWingedShark··on Giving Ada a Chance
GNAT debuted in 1995, 25 years ago. Some 12 years after the 1983 standard.
OneWingedShark··on Giving Ada a Chance
> I use PL/SQL a fair bit, which was inspired by Ada. I have a bit of a project-idea here: PL/SQL+Ada+VHDL all together in an IDE.

> Unfortunately, the designers did not bring over > ShortName is New ReallyLongAndAwkardName; Do you mean renames? Package Text renames Ada.Strings.Fixed;

IIRC, RENAME is in the keywords list for PL/SQL.

OneWingedShark··on Giving Ada a Chance
Awesome, you wouldn't still have a copy of your Ada compiler's source do you?
OneWingedShark··on Giving Ada a Chance
There's a LOT of things that it's not necessary for; watch this video: https://archive.fosdem.org/2016/schedule/event/ada_memory/
OneWingedShark··on Giving Ada a Chance
>I get what you're saying, but learning C teaches you about the C memory model instead of "real machines". No. C doesn't do that, not at all; see: https://queue.acm.org/detail.cfm?id=3212479 If you want to get to the down and dirty, and quickly, without nearly all the "Gotcha!" inherit in C, FORTH is the way to go.

>C was designed for portability across different architectures Absolute bullshit. This is a claim that has been going on for far too long, the whole "portable assembler" myth. IEEE694-1985 is a portable assembler, hell read "Using a high level language as a cross assembler" ( DOI: 10.1145/954269.954277 ), for that matter.

>and, believe it or not, was considered high-level and abstract at one time. The "gotcha!"-factor was increasingly ignored when I was learning about computer languages, but I had an advantage in having my first language be Turbo Pascal and self-taught using the manual and compiler.

> But I agree that learning C is valuable because I believe that learning about manual memory management is valuable. That's doable much easier in Ada, Forth, or BLISS. C is becoming more and more of a liability, to the point I would say that it has no real value in any professional setting, and an incredibly limited one in the academic.

OneWingedShark··on Coding in Ada: Strings (IV) Unbounded to String
What a lot of people don't understand is the reason that Ada has so many string-types, and the answer is pretty simple: usage.

Fixed: The simple string-as-an-array approach. Bounded: The maximum, but variable-size approach; analogous to many database string-field data-definitions. Unbounded: The variable-at-runtime approach.

You can generally use the Fixed form for your operations, thanks to the String-array being unbounded, and having functions returning your perfectly-sized results.

My biggest issue with the Strings packages are the [[Wide_]Wide_]String hierarchy: I would have much rather had this be a set of instantiated generics with the appropriate parameters (eg passing in a CHARACTER type and UPPERCASE/LOWERCASE functions, etc)... but doing that would have required redesigning the STRINGS package back at the Ada95 era.

OneWingedShark··on First beta release of Alire, the package manager for Ada/SPARK
> So I wish that instead of using TOML files, the dependencies would be specified in the gprbuild project files themselves. The syntax/options of GPR files would probably have to be extended, but it would be nice to have only one layer of config files that contains everything needed to build an Ada library/project.

There are several problems with GPR. The first is that it's GNAT-only and no other compiler would recognize it. The second is more technical: GPR is more "stringly-typed" than it ought to be, and thus despite a somewhat Ada-like syntax it isn't nearly as nice as Ada-source.

I've been mulling the idea of leveraging Ada's generic-system for a method to use as a Project specification/definition -- if you could have an Ada generic as a project-file, then you could [re]use the compiler/syntax-checker... I've also sketched out a way that Generic-parameters could be used by a project-builder program, generating an appropriate menu.

OneWingedShark··on Airbus Chooses GNAT Pro Ada for Development of Unmanned Aerial System
> Ada seems pretty nice, but it does not have a borrow checker, does it? IIUC, there is a SPARK implementation that does: https://blog.adacore.com/using-pointers-in-spark / https://www.adacore.com/uploads/techPapers/Safe-Dynamic-Memo...

That said, there are whole classes of problems where, thanks to Ada's design, you don't even NEED pointers where you would in C or similar languages: http://video.fosdem.org/2016/aw1124/memory-management-with-a...

> I think deallocation is considered unsafe? This too depends; Ada was designed so that a garbage-collector could be used, even in Ada83, most implementations do not take advantage of this. (There are JVM and DOTNET implementations where GC is required though.)

To achieve safe deallocation it is often delegated to scopes so that exiting a scope clears out all the memory you were using; see stack-allocation, pools/subpools, and local-declarations/inline-declarations.

OneWingedShark··on Airbus Chooses GNAT Pro Ada for Development of Unmanned Aerial System
They are typically pretty good; the design helps the compiler to not have to re-compile everything any time something is changed, so most of your variance is going to boil down to "how much did you change."

That said, Delphi is blazing fast so Ada will seem a bit slower, typically… but [IME] it's generally not going to be something as slow as a lot of C++ programs.

← PreviousPage 2 of 3Next →