I cant seem to find any information on how to do this. Does anyone know how I could pass an array to a procedure just like you would a character or integer?
And example would be amazing.
First, you have to have a named array type. An anonymous type won't work (anonymous types are a bad idea in any case).
As an example, there is an array type named String declared in package Standard as:
type String is array (Positive range <>) of Character;
String is no different from any other array type. You pass a String (or any other array type) to a subprogram exactly the way you do any other type:
function Index (Source : in String; Pattern : in String) return Natural;
procedure To_Upper (Source : in out String);
As Jeffrey stated, you need a type name. There are some places in the Ada syntax where you need a simple type name with no embellishments, and other places where you can have anonymous array types or names with other constraints attached to them. Parameter declarations are one place where the type must be a simple name (except that for access types you can add not null, which you may not have learned about yet, but that's the only exception). Thus, you can't say
procedure joiningTo(A: in integer; B: array(1..12, 1..12) of character) is
or
procedure Print_Field(Data : String(1..30)) is
since the name must be a simple type name in this context. There are a couple solutions, and you need to choose which one is more appropriate. If it makes sense that joiningTo could work correctly with array of any length and width, define an unconstrained array type somewhere in your program:
type Two_Dimensional_Char_Array is array (positive range <>, positive range <>) of character;
procedure joiningTo(A : in integer; B : in Two_Dimensional_Char_Array) is
If, on the other hand, it's a requirement that the parameter be exactly 12-by-12, you can define a type or subtype name that includes the constraint:
type Twelve_Square is array (1..12, 1..12) of character;
procedure joiningTo(A : in integer; B : in Twelve_Square) is
or
type Two_Dimensional_Char_Array is array (positive range <>, positive range <>) of character;
subtype Twleve_Square is Two_Dimensional_Char_Array (1..12, 1..12);
procedure joiningTo(A : in integer; B : in Twelve_Square) is
(Side note: The standard naming convention in Ada, since Ada 95, is to upper-case the first letter of each word [usually] and separate words with _ characters; this is different from the Java or C communities where _ characters are frowned upon. Also, it's important to note that, unlike Java or C, Ada does not care about letter case in identifiers.)
Related
I want to create a structure in Julia which contains two floating point variables (coorx, velx) and one vector array of two elements which contains gradients with two elements, my idea is as follows:
struct part_struct
coorx::Float64
velx::Float64
gradx::Vector{Float64}(undef,2)
end
However, when I try to create an array of 10 of such structures:
num = 10
part = Array{part_struct,1}(undef, num)
I get the error:
TypeError: in part_struct, in type definition, expected Type, got a value of type Array{Float64,1}
How could I create such a structure in Julia?
you should put the type of the array in the struct, like that:
struct PartStruct
coorx::Float64
velx::Float64
gradx::Vector{Float64}
end
Note that you can't restrict the size of a Vector in a struct. To do so, you can use a Tuple instead (it should also have better performance):
struct PartStruct
coorx::Float64
velx::Float64
gradx::NTuple{2, Float64} # (equivalent to Tuple{Float64, Float64})
end
This is an immutable struct, which might not be what you want
I want to append an index to an Integer array during a loop. Like add 3 to [1,2] and get an array like [1,2,3]. I don't know how to write it in the format and I cannot get the answer on the Internet.
You can use Vectors to do the something similar using the & operator. You can access the individual elements just like an array, though you use () instead of []. Or you can just use a for loop and get the element directly.
See the below example:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure jdoodle is
-- Create the package for a vector of integers
package Integer_Vectors is new Ada.Containers.Vectors(Positive,Integer);
-- Using subtype to make just the Vector type visible
subtype Vector is Integer_Vectors.Vector;
-- Make all the primitive operations of Vector visible
use all type Vector;
-- Create a variable
V : Vector;
begin
-- Add an element to the vector in each iteration
for i in 1..10 loop
V := V & i;
end loop;
-- Show the results
for Element of V loop
Put_Line(Element'Image);
end loop;
-- Print the 2nd element of the array
Put_Line(Integer'Image(V(2)));
end jdoodle;
Ada arrays are first class types, even when the array type is anonymous. Thus a 2-dimensional array is a different type than a 3-dimensional array. Furthermore, arrays are not defined by directly specifying the number of elements in a dimension as they are in languages derived from C.
For instance, if you define a 2-dimensional array such as
type array_2d is array (Integer range 0..1, Integer range 1..2);
You have defined an array with a first range of 0..1 and a second range of 1..2. This would be a square matrix containing 4 elements.
You cannot simply add another dimension to an object of the type array_2d described above. Such an array must be of a different type.
Furthermore, one cannot change the definition of an array object after it is created.
Ok, so while this is a simple question it gets into the interesting details of design very quickly. The first thing is that an array "always knows its bounds" -- this language design element impacts the usage of the language profoundly: instead of having to pass the length of the array as a parameter, and possibly going out-of-sync, like in C you simply pass the array and let the "it knows its bounds" take care of the management.
Second, the Array is always static-length, meaning it cannot be changed once created. Caveat: Creating an array can be done in a "dynamic" setting, like querying user-input.
Third, if the subtype is unconstrained than it can have "variable" length. -- This means that you can have something like Type Integer_Vector is Array(Positive Range <>) of Integer and have parameters that operate on any size value passed in (and return-values that can be any size). This, in turn, means that your handling of such subtypes tends itself toward the more general.
Fourth, all of these apply and combine so that a lot of the 'need' for dynamically sized arrays aren't needed -- yes, there are cases where it is needed, or where it is more convenient to have a single adjustable object; this is what Ada.Containers.Vectors addresses -- but in the absence of needing a truly dynamically-sizing object you can use processing for achieving your goals.
Consider the following example:
Type Integer_Vector is Array(Positive range <>) of Integer;
Function Append( Input : Integer_Vector; Element : Integer ) return Integer_Vector is
( Input & Element );
X : Constant Integer_Vector:= (1,2);
Y : Integer_Vector renames Append(X, 3);
These three design choices combine to allow some intere
This (declaration) code raises a storage error:
type Vector is array (Integer range <>) of Integer;
type Array_Starting_At_One (Max : Integer := 0) is
record
Mat : Vector (1 .. Max);
end record;
X : Array_Starting_At_One;
I can't figure out why. If I specify the default, as in X : Array_Starting_At_One (Max => 0); the error disappears, although the Array_Starting_At_One type specification still triggers a warning that creation of such objects may raise Storage_Error.
I am not even trying to store a single bit, so this error doesn't make any sense to me:
raised STORAGE_ERROR : System.Memory.Alloc: object too large
When a variable is declared using the default discriminant, then the discriminant can later be changed via an assignment. This means that the compiler (at least GNAT does this) will allocate (on the stack) enough room to hold an object with any discriminant up to the maximum allowed value (Integer'Last in this case).
Either increase your stack size (not neccessarily recommended), or use a different subtype more suited to your problem:
subtype Foo is Integer range 1..10;
type Vector is array (Foo range <>) of Integer;
Certainly any array with an index range of 1..Integer'Last could raise Storage_Error. The compiler is warning you of this possibility. Try restricting the index range for your array type such as:
subtype Indices is Integer range 0..1024;
type Vector is Array (Indices range <>) of Integer;
type Array_Ending_At (Max : Indices := 0) is
record
Mat : Vector(1..Max);
end record;
As you notice, this is a compiler issue. The Janus/Ada compiler would accept your code without complaint or run-time exception.
Your variable X is an unconstrained object; the discriminant (and so the size of the object) can be changed by full-record assignment. The ARM is silent about how such things should be implemented. GNAT has chosen to allocate enough space for the largest possible value; since X is allocated on the stack, there will not be enough space for it with GNAT's default stack size (if you allocate it on the heap, you might not have a problem). Janus instead allocates only enough space for the current value, which may result in X.Mat being implicitly allocated on the heap.
The Janus way is more developer-friendly and acceptable for most applications, where the developer doesn't care where things are allocated, but there are situations where implicit heap allocation cannot be accepted, so the GNAT way is more general.
I am trying to define a dictionary that takes strings as keys and any values. Thus, I try to use Dict{String, <:Any} as type. However, the return value to that expression is
> Dict{String,#s27} where #s27
Moreover, if I try to define a dictionary of that type I get an error:
For Dict{String,<:Any}() I get ERROR: MethodError: no method matching Dict{String,#s28} where #s28()
For Dict{String,<:Any}("aa"=>42) I get ERROR: MethodError: no method matching Dict{String,#s29} where #s29(::Pair{String,Int64})
I also tried using Dict{String} (which should be equivalent), with similar results.
What am I missing about types of dictionaries here?
What you are looking for is a Dict{String, Any}, not Dict{String, <:Any}. The first one is a concrete type, namely a dict that takes strings as keys and anything as values. The second, Dict{String, <:Any} is not actually a concrete type, but a unionall type. That means it is an infinite set of types. And the error you are seeing is that you can't instantiate this set of types. You can only instantiate a concrete (leaf) type.
Another way of writing Dict{String, <:Any} is Dict{String, T} where T <: Any, and that makes it a little clearer what it is. It is the set of all types of Dict that has String as they key type and a type that is a subtype of Any as their value type.
So for example we can say that Dict{String, Int} is a subtype of the infinite set Dict{String, <:Any}.
Edit: One use of unionall types is to be able to restrict the kind of type you take to fine grained level. For example, a counting function may look like this:
function count_stuff(stuff, counter::Dict{T, <:Integer}) where T
# stuff here¨
end
The second argument here is a Dict that has some subtype of Integer as a value type and any type as a key type. That's basically what you'd need to use the dict as a counter.
How to increment an address of access type like a pointer in C? I am new to Ada...
procedure main is
type myarr is array(1..5)of integer; --creating array of 5 integer.
myarr_var:aliased myarr:=(2,5,7,9,0); --setting 5 values
type my_access is access all myarr; --creating access type (pointer)
var:my_access:=myarr_var'access; --holding address of 5 integer
begin;
-- since var holds the address of myarr_var now i want to increment
-- the address by adding 1 to print next value (5) as we do in c?
put((var+1).all); --???
-- i know this is bad but how to increment its base address of
-- var(pointer) so that it will point to next element 5?
end main;
Instantiate Interfaces.C.Pointers to do C-style pointer arithmetic in Ada.
Best explained by example:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Pointers;
procedure Access_Pointer_Arithmetic is
type Myarr_Indices is range 1 .. 5;
type Myarr is array (Myarr_Indices range <>) of aliased Integer;
Myarr_Terminator : constant Integer := 0;
package Myarr_Pointer_Arithmetic is new Interfaces.C.Pointers
(Myarr_Indices, Integer, Myarr, Myarr_Terminator);
use Myarr_Pointer_Arithmetic;
Myarr_Var : aliased Myarr := (2, 5, 7, 9, 0);
Var : Myarr_Pointer_Arithmetic.Pointer :=
Myarr_Var(Myarr_Var'First)'access;
begin
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Increment(Var);
Put_Line(Integer'Image(Var.all));
Var := Var - 2;
Put_Line(Integer'Image(Var.all));
end Access_Pointer_Arithmetic;
Running it:
C:\Ada\Sandbox\access_pointer_arithmetic
2
5
7
9
5
This package provides single increment/decrement, addition and subtraction of ptrdiff_t, and both terminator-specified and fixed length element array retrieval.
(Mind running off the end of the array... :-)
UPDATE : I just found out that there's a standard package Interfaces.C.Pointers that directly supports C-style pointer arithmetic, and now I see that Marc C.'s accepted answer covers its usage. You can probably ignore my answer, which discusses how you might do pointer arithmetic in Ada if Interfaces.C.Pointers didn't exist (which, in earlier versions of the language, it doesn't).
If you really want to do C-style pointer arithmetic on Ada access types, you can use the generic package System.Address_To_Access_Conversions to convert an object pointer type to System.Address, and the System.Storage_Elements package to perform C-like arithmetic on System.Address values.
Note that the target object type is a parameter to the System.Address_To_Access_Conversions generic package. The package itself defines the access type. You can't define your own access type and use it (at least not directly).
Keep in mind that C pointer arithmetic is defined in units of the size of the pointed-to object. So given:
int arr[10];
int *ptr = &arr[0];
the pointer value ptr + 3 points to arr[3], which is three int-sized chunks of memory past the location to which ptr points not necessarily three bytes. The "+" and "-" operators in System.Storage_Elements work with offsets in storage elements (which are very likely equivalent to C's "bytes").
So if you have an Ada pointer, um, I mean access value, that refers to an element of an array of Integers, then advancing to the next element of that array requires:
Using System.Address_To_Access_Conversions to convert the access type to System.Address;
Using the overloaded "+" operator in System.Storage_Elements to add the size of an Integer in bytes (Integer'Max_Size_In_Storage_Elements) to the System.Address value; and
Using System.Address_To_Access_Conversions again to convert the System.Address value back to your access type.
An alternative might be to write C code to do whatever pointer arithmetic you need, and use Interfaces.C to call that code from your Ada program.
But it's very likely that you don't need to do pointer arithmetic in Ada. C has pointer arithmetic in the core language; it even defines array indexing in terms of pointer arithmetic. Ada does not. There's rarely a good reason to perform pointer arithmetic in Ada. Just let arrays be arrays, and let the compiler figure out how to generate the best code to access their elements. (That code will likely involve pointer arithmetic on the CPU instruction level.)