How to return a Forward_Iterator of a Hashed_Set in Ada? - iterator

I want to return a Forward_Iterator over the elements of an hashed_set in Ada, like in the code below:
with Ada.Containers.Hashed_Sets;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Hash;
with Ada.Text_IO; use Ada.Text_IO;
procedure debug is
package my_set is new Ada.Containers.Hashed_Sets
(Element_Type => Unbounded_String,
Hash => Ada.Strings.Unbounded.Hash,
Equivalent_Elements => "=");
function get_Iterator
(some_set : my_set.set)
return my_set.Set_Iterator_Interfaces.Forward_Iterator'Class is --' Highlight fix
begin
return some_set.Iterate;
end;
set_1 : my_set.set;
begin
set_1.insert(To_Unbounded_String("element"));
for E in get_Iterator (some_set => set_1) loop
put_line ("i iterate!");
end loop;
end debug;
The problem is that the code raises a program error
"raised PROGRAM_ERROR : debug.adb:6 finalize/adjust raised exception" which i do not understand ... (im using GNAT Ada GPL 2014 under Ubuntu 14.04)
Is there a way to repair the code? Or is there another possibility to return an iterator over a hashed_set? An application for this is e.g. the case when the hashed_set is part of an private record and it should only be possible to iterate the elements from outside, but not to change the set itself.
Thanks in advance!
PS: This is my first question here, so if you have any tips for improving the question, please tell me :)

I think you have found a bug in GNAT. Please submit your example to the GCC bug database.
But why do you want an explicit iterator object? Usually you just loop over the container leaving the compiler to mess with handling the iterator object.

I just wanted to post my solution to this problem.
I had the possiblity to check the problem with Gnat Pro 7.2.x and I does not appear anymore. But If you do I similar approach using a Hashed_Map instead of a Hashed_Set, it was still there.
Since I also got access to the GNATtracker, I postet my problem there and was told that this is indead a compiler bug. The compiler is generating an incorrect accessibility check at the Get_Iterator function.
Hence, the workaround that was suggested, was to just suppress the corresponding check for the function:
function get_Iterator
(some_set : my_set.set)
return my_set.Set_Iterator_Interfaces.Forward_Iterator'Class is --' Highlight fix
pragma Suppress (Accessibility_Check); -- workaround to suppress buggy check
begin
return some_set.Iterate;
end;
This workaround works for me with Gnat Pro 7.2.x and Gnat GPL 2014 for both, Hashed_Sets and Hashed_Maps.

Related

Compilation error only when using the repl

I am getting an error only when the code is entered line by line in the repl. It works when the whole program is pasted at once, or from the command line.
class A {
method a () {
return 1;
}
}
class B {
method b () {
return 2;
}
}
This is the error statement:
===SORRY!=== Error while compiling:
Package 'B' already has a method 'b' (did you mean to declare a multi method?)
This screen shot might make it clearer. On the left I just pasted the code, and on the right I entered it line by line. The code is still working but what is causing the error?
For some reason, I could not reproduce this using just one class.
I can reproduce that error, and looks like a REPL bug, or simply something the REPL is not prepared to do. This, for instance, will also raise an exception:
class A {
method a() {
return 1;
}
};
class foo {
has $.bar = 3;
};
In either form, either pasting it directly or in pieces. It's always the second class. It's probably related to the way EVAL works, but I really don't know. At the end of the day, the REPL can only take you so far and I'm not totally sure this is within the use case. You might want to use Comma or any other IDE, like emacs, for anything that's more complicated than a line; Comma also provides help for evaluating expressions, and even grammars.
I think Comma is the bees knees. And I almost never use the repl. But I enjoy:
Golfing Your example is a more than adequate MRE. But I love minimizing bug examples.
Speculating I think I can see what's going on.
Searching issue queues Rakudo has two issue queues on GH: old and new.
Spelunking compiler code Rakudo is mostly written in Raku; maybe we can work out what this problem is in the REPL code (which is part of the compiler)?
Golfing
First, the bug:
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.03.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.03.
To exit type 'exit' or '^D'
> # 42
Nil
> { subset a
*
===SORRY!=== Error while compiling:
Redeclaration of symbol 'a'.
at line 3
------> <BOL>⏏<EOL>
Commentary:
To get on the fairway, enter any line that's not just whitespace, and press Enter.
Pick the right iron; open a block with {, declare some named type, and press Enter. The REPL indicates you're on the green by displaying the * multi-line prompt.
To sink the ball, just hit Enter.
Second, golfing in aid of speculation:
> # 42
Nil
> { BEGIN say 99
99
* }
99
>
(BEGIN marks code that is to be run during compilation as soon as the compiler encounters it.)
Speculating
Why does the initial # 42 evaluation matter? Presumably the REPL tries to maintain declarations / state (of variables and types etc) during a REPL session.
And as part of that it's presumably remembering all previous code in a session.
And presumably it's seeing anything but blank lines as counting as previous code.
And the mere existence of some/any previous code somehow influences what state the REPL is maintaining and/or what it's asking the compiler to do.
Maybe.
Why does a type declaration matter when, say, a variable declaration doesn't?
Presumably the REPL and/or compiler is distinguishing between these two kinds of declaration.
Ignoring the REPL, when compiling code, a repeated my declaration only raises a warning, whereas a repeated type declaration is an error. Quite plausibly that's why?
Why does a type declaration have this effect?
Presumably the type successfully compiles and only after that an exception is thrown (because the code is incomplete due to the missing closing brace).
Then the REPL asks the compiler to again try to compile the multi-line code thus far entered, with whatever additional code the user has typed (in my golf version I type nothing and just hit Enter, adding no more code).
This repeated compile attempt includes the type declaration again, which type declaration, because the compilation state from the prior attempt to compile the multi-line code is somehow being retained, is seen by the compiler as a repeat declaration, causing it to throw an exception that causes the REPL to exit multi-line mode and report the error.
In other words, the REPL loop is presumably something like:
As each line is entered, pass it to the compiler, which compiles the code and throws an exception if anything goes wrong.
If an exception is thrown:
2.1 If in multi-line mode (with * prompt), then exit multi-line mode (go back to > prompt) and display exception message.
2.2 Else (so not in multi-line mode), if analysis (plausibly very basic) of the exception and/or entered code suggests multi-line mode would be useful, then enter that mode (with * prompt). In multi-line mode, the entire multi-line of code so far is recompiled each time the user presses Enter.
2.3 Else, display exception message.
(Obviously there's something else going on related to initialization given the need to start with some evaluation to manifest this bug, but that may well be a completely distinct issue.)
Searching
I've browsed through all open Rakudo issues in its old and new queues on GH that match 'repl'. I've selected four that illustrate the range of difficulties the REPL has with maintaining the state of a session:
REPL loses custom operators. "Interestingly, if a postfix operator like this is exported by a module which is loaded by the REPL, the REPL can successfully parse that operator just once, after which it will fail with an error similar to the above." Is this related to the way the bug this SO is focused on doesn't manifest until it's a second or later evaluation?
Perl6 REPL forgets the definition of infix sub. Looks like a dupe of the above issue, but includes extra debugging goodies from Brian Duggan. ❤️
REPL messes up namespaces when Foo is used after Foo::Bar.
In REPL cannot bind to scalars declared on earlier lines.
One thing I haven't done is checked whether these bugs all still exist. My guess is they do. And there are many others like them. Perhaps they have a somewhat common cause? I've no idea. Perhaps we need to look at the code...
Spelunking
A search of the Rakudo sources for 'repl' quickly led to a REPL module. Less than 500 lines of high level Raku code! \o/ (For now, let's just pretend we can pretty much ignore digging into the code it calls...)
From my initial browser, I'll draw attention to:
A sub repl:
sub repl(*%_) {
my $repl := REPL.new(nqp::getcomp("Raku"), %_, True);
nqp::bindattr($repl,REPL,'$!save_ctx',nqp::ctxcaller(nqp::ctx));
$repl.repl-loop(:no-exit);
}
Blame shows that Liz added this a couple months ago. It's very tangential to this bug, but I'm guessing methods and variables with ctx in their name are pretty central to things so this is hopefully a nice way to start pondering that.
method repl-eval. 30 lines or so.
REPL: loop { ... }. 60 lines or so.
That'll do for tonight. I'll post this then return to it all another day.

compile error related to "in expansion of macro ‘CHKERRQ"’

I have this compiler error related to "in expansion of macro ‘CHKERRQ’" from PETSC whenever I call "CHKERRQ", I am not sure what causes it, could anyone please give any advice?
Thanks for your help in advance,
Feng
I solved the problem in the end. The return type of my function is void. I need to set the return type of my function, which calls lots of PETSC routines, to PetscErrorCode.

How do I link a custom dll in Ada?

So this is a simple project I put together just to test before doing some cool stuff with it later. The eventual goal is to make the program able to handle modularity through awesome dll kung fu.
But, baby steps. Right now I just want to make the thing link.
Here I have Adder.ads:
package Adder is
function Add(A : Integer; B : Integer) return Integer;
end Adder;
And the respective Adder.adb:
package body Adder is
function Add(A : Integer; B : Integer) return Integer is
begin
return A + B;
end Add;
end Adder;
Exciting, I know.
I've seen several different tutorials on how to do this, and none of them agree, but taking a cue from this one, I came up with these commands:
gnatmake -c Adder.adb
gcc -shared -shared-libgcc -o Adder.dll Adder.o
This at least generates a dll. I dunno if it generates one that will actually work or if the problem is with the main exe though.
Now the main exe, I have kept everything in a separate directory so gnat doesn't try to cheat and use the .ali and .o files. Then you copy the dll into the directory before trying to build. I've tried this tweaking lots of different ways and gotten several different errors, but here is what I have right now.
Main.adb:
with Adder_Spec; use Adder_Spec;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
begin
Put_Line(Integer'Image(Add(3,4)));
end Main;
Yay most useless program ever. Now, knowing I'm supposed to have a spec for the dll, I came up with the aforewith'd Adder_Spec.ads:
package Adder_Spec is
function Add(A : Integer; B : Integer) return Integer;
private
pragma Import(Ada, Add, "Add");
end Adder_Spec;
Now, like I said I've tried this a bunch of different ways, sometimes omitting the third import parameter, other times omitting the import altogether, sometimes keeping the import but not separating it into the private part, you name it. I've also tried playing with the compile command several ways, but here's the most recent one:
gnatmake Main.adb -bargs -shared -largs -lAdder
With this particular command it spits out an "Undefined reference to 'Add'" error. If I add the -v flag, it doesn't provide much more useful information.
Checking gnatmake --help shows me that the default mode is gnat 2012, if that makes any difference. It probably shouldn't, as I've tried compiling with the flags for 2005 and 95, too.
So... can anybody savvy enough spot the problem? Thanks in advance.
If you want to say
package Adder_Spec is
function Add(A : Integer; B : Integer) return Integer;
private
pragma Import(Ada, Add, "Add");
end Adder_Spec;
when importing the DLL, then you have to say
package Adder is
function Add(A : Integer; B : Integer) return Integer;
pragma Export (Ada, Add, "Add");
end Adder;
when building it.
GNAT’s default linker name for the generated Add would be (I think) adder__add; you should be able to see what it is using nm Adder.o.
I suggest that you follow the instructions in "Ada Plug-ins and Shared Libraries" (part 1, part 2) from AdaCore.
I've used the technique described there, and it worked quite fine.

Does ReSharper find when you delete an item in an enumeration?

I'm sure at some point we've all written some code like this:
For Each datVehicle In datVehicles
If datVehicle.ID = -1 Then
datVehicles.Remove(datVehicle)
End If
Next
Which compiles just fine but throws runtime exception because you can't delete an item in an enumeration. Does ReSharper catch things like this?
Resharper 6.1 on VS 2010 does not catch it out-of-teh-box. Resharper does not think it is quite Skeet-code tho as it suggests converting to linq.
No version of ReSharper catches this problem. To create custom pattern that can warn about this condition is not easy because your iteration code can be pretty complex.
If you want to create a custom pattern I would suggest to create a suggestion (may be a warning). Your pattern would look something like that:
$ICOLLECTION$.Remove($arg$)
Where $ICOLLECTION$ is an expression of type System.Collections.Generic.ICollection and $arg$ is an argument placeholder.
This way you'll always have a suggestion ( or warning).
I know that the question is about ReSharper only but I want to show the workaround to complete my answer. The workaround for this problem is to use RemoveAll. Here's the example in C#:
datVehicles.RemoveAll(x => x.Id == -1);
I don't think it does automatically, but you could easily create a custom pattern to identify this for you. See: https://blog.jetbrains.com/dotnet/2010/08/19/highlighting-custom-patterns-with-resharper/

Ignore Ada Function Return Values

Is there a way to ignore return values in Ada functions?
I have a function which imports from an Intrinsic.
subtype int32 is Interfaces.Interger_32;
function Intrinsic_Sync_Add_And_Fetch
(P : access int32; I : int32) return int32;
pragma Import(
Intrinsic,
Intrinsic_Sync_Add_And_Fetch,
"__sync_add_and_fetch_4");
If I want to use this in a procedure, I need to accept the return value or I will get a compiler error:
cannot use function Intrinsic_Sync_Add_And_Fetch in procedure call.
But, if I create a variable that simply takes the return value of the function and is never used then I get compiler warnings. Obviously, I'd rather avoid those.
I can't very well assign the value back to the value I'm adding to; this would undermine the point of the add operation being atomic.
There is the option of taking the value and doing something with it, like:
val := Intrinsic_Sync_Add_And_Fetch(...);
if val := 0 then null; end if;
It forces the code to compile without errors or warnings, but it seems stupid to me. How can I "get around" this language feature and safely ignore the return value?
Edit: What is __sync_add_and_fetch_4?
This is a built-in atomic operation available on Intel CPUs. As such, part of my Autoconf/Automake process would be deciding if the operation is available, and use a fallback implementation, which involves a critical section, if it's not.
You can read about this and similar operations in GCC's section on atomic builtins.
The __sync_add_and_fetch_4 does pretty much exactly what it says. In C, it would look something like this:
int32_t __sync_add_and_fetch_4(int32_t *ptr, int32_t value) {
*ptr += value;
return *ptr;
}
So it's an atomic addition operation, which returns the result of the addition. Basically, it's an atomic += operator. The _4 means that it takes a 4-byte integer.
Edit: I understand that I could probably just switch off that particular compiler warning, but that always feels dirty to me. If there's a solution available that allows me to continue using -Wall -Werror then I'd love to see it.
declare
dummy : constant return_type := my_function;
pragma Unreferenced (dummy);
begin null; end;
or write a wrapper procedure.
If you never want to reference the return value, why not declare the subprogram as a procedure? The value is going to be returned in a register, so throwing it away won’t cause a lot of grief. (I stand to be corrected on this one!)
subtype int32 is Interfaces.Integer_32;
procedure Intrinsic_Sync_Add_And_Fetch
(P : access int32; I : int32);
pragma Import(
Intrinsic,
Intrinsic_Sync_Add_And_Fetch,
"__sync_add_and_fetch_4");
You said you're only targeting the GNAT compiler. The GNAT User's Guide says:
Note that a special exemption applies to variables which contain any of the substrings DISCARD, DUMMY, IGNORE, JUNK, UNUSED, in any casing. Such variables are considered likely to be intentionally used in a situation where otherwise a warning would be given, so warnings of this kind are always suppressed for such variables.
So the simplest solution to your problem is :
unused := Intrinsic_Sync_Add_And_Fetch(...);
Though you might want to wrap that in a procedure if you are going to use it more than a couple of times :
procedure Intrinsic_Sync_Add_And_Fetch(P : access int32; I : int32) is
unused : int32;
begin
unused := Intrinsic_Sync_Add_And_Fetch(P : access int32; I : int32);
end Intrinsic_Sync_Add_And_Fetch;
i don't know of any way to ignore the return value of a function in Ada: the language has been especially designed to force you to store those return values.
personally, i would store the return value and ignore any warning regarding the use of the variable. anyway, the said warning is quite strange since the variable is indeed used to store the return value.