How do I use counting related instances instead of attributes in OCL - collections

For example say if I had a library and a precondition of issuing a book to a borrower was that it can only be issued if it is not reference only and is not already on loan to someone else, I could say:
context Copy::issue() : Boolean
pre: (referenceCopy and onLoan) == false
But that would use the attribute onLoan for the book copy. Instead I want to say this with collection-methods to count related entities?

For example, you can use isEmpty()
context Copy::issue() : Boolean
pre: not self.referenceCopy and self.borrowers->isEmpty()
or count()
context Copy::issue() : Boolean
pre: not self.referenceCopy and self.borrowers->count() = 0
You can omit the context variable self if you want.

Related

Is it bad practice to provide your own setter or should I use setproperty?

Suppose if I had the following Employee struct:
mutable struct Employee
_id::Int64
_first_name::String
_last_name::String
function Employee(_id::Int64,_first_name::String,_last_name::String)
# validation left out.
new(_id,_first_name,_last_name)
end
end
If I wanted to implement my own setproperty!() I can do:
function setproperty!(value::Employee,name::Symbol,x)
if name == :_id
if !isa(x,Int64)
throw(ErrorException("ID type is invalid"))
end
setfield!(value,:_id,x)
end
if name == :_first_name
if is_white_space(x)
throw(ErrorException("First Name cannot be blank!"))
end
setfield!(value,:_first_name,x)
end
if name == :_last_name
if is_white_space(x)
throw(ErrorException("Last Name cannot be blank!"))
end
setfield!(value,:_last_name,x)
end
end
Have I implemented setproperty!() correctly?
The reason why I use setfield!() for _first_name and _last_name, is because if I do:
if name == :_first_name
setproperty!(value,:_first_name,x) # or value._first_name = x
end
it causes a StackOverflowError because it's recursively using setproperty!().
I don't really like the use of setproperty!(), because as the number of parameters grows, so would setproperty!().
It also brings to mind using Enum and if statements (only we've switched Enum with Symbol).
One workaround I like, is to document that the fields are meant to be private and use the provided setter to set the field:
function set_first_name(obj::Employee,first_name::AbstractString)
# Validate first_name before assigning it.
obj._first_name = first_name
end
The function is smaller and has a single purpose.
Of course this doesn't prevent someone from using setproperty!(), setfield!() or value._field_name = x, but if you're going to circumvent the provided setter then you'll have the handle the consequences for doing it.
Of course this doesn't prevent someone from using setproperty!(), setfield!() or value._field_name = x, but if you're going to circumvent the provided setter then you'll have the handle the consequences for doing it.
I would recommend you to do this, defining getter,setter functions, instead of overloading getproperty/setproperty!. on the wild, the main use i saw on overloading getproperty/setproperty! is when fields can be calculated from the data. for a getter/setter pattern, i recommend you to use the ! convention:
getter:
function first_name(value::Employee)
return value._first_name
end
setter:
function first_name!(value::Employee,text::String)
#validate here
value._first_name = text
return value._first_name
end
if your struct is mutable, it could be that some fields are uninitialized. you could add a getter with default, by adding a method:
function first_name(value::Employee,default::String)
value_stored = value._first_name
if is_initialized(value_stored) #define is_initialized function
return value_stored
else
return default
end
end
with a setter/getter with default, the only difference between first_name(val,text) and first_name!(val,text) would be the mutability of val, but the result is the same. useful if you are doing mutable vs immutable functions. as you said it, the getproperty/setproperty! is cumbersome in comparison. If you want to disallow accessing the fields, you could do:
Base.getproperty(val::Employee,key::Symbol) = throw(error("use the getter functions instead!")
Base.setproperty!(val::Employee,key::Symbol,x) = throw(error("use the setter functions instead!")
Disallowing the syntax sugar of val.key and val.key = x. (if someone really want raw access, there is still getfield/setfield!, but they were warned.)
Finally, i found this recomendation in the julia docs, that recommends getter/setter methods over direct field access
https://docs.julialang.org/en/v1/manual/style-guide/#Prefer-exported-methods-over-direct-field-access

New to coding, Can not get this to work [duplicate]

This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I've been using the == operator in my program to compare all my strings so far.
However, I ran into a bug, changed one of them into .equals() instead, and it fixed the bug.
Is == bad? When should it and should it not be used? What's the difference?
== tests for reference equality (whether they are the same object).
.equals() tests for value equality (whether they contain the same data).
Objects.equals() checks for null before calling .equals() so you don't have to (available as of JDK7, also available in Guava).
Consequently, if you want to test whether two strings have the same value you will probably want to use Objects.equals().
// These two have the same value
new String("test").equals("test") // --> true
// ... but they are not the same object
new String("test") == "test" // --> false
// ... neither are these
new String("test") == new String("test") // --> false
// ... but these are because literals are interned by
// the compiler and thus refer to the same object
"test" == "test" // --> true
// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true
// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true
You almost always want to use Objects.equals(). In the rare situation where you know you're dealing with interned strings, you can use ==.
From JLS 3.10.5. String Literals:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
Similar examples can also be found in JLS 3.10.5-1.
Other Methods To Consider
String.equalsIgnoreCase() value equality that ignores case. Beware, however, that this method can have unexpected results in various locale-related cases, see this question.
String.contentEquals() compares the content of the String with the content of any CharSequence (available since Java 1.5). Saves you from having to turn your StringBuffer, etc into a String before doing the equality comparison, but leaves the null checking to you.
== tests object references, .equals() tests the string values.
Sometimes it looks as if == compares values, because Java does some behind-the-scenes stuff to make sure identical in-line strings are actually the same object.
For example:
String fooString1 = new String("foo");
String fooString2 = new String("foo");
// Evaluates to false
fooString1 == fooString2;
// Evaluates to true
fooString1.equals(fooString2);
// Evaluates to true, because Java uses the same object
"bar" == "bar";
But beware of nulls!
== handles null strings fine, but calling .equals() from a null string will cause an exception:
String nullString1 = null;
String nullString2 = null;
// Evaluates to true
System.out.print(nullString1 == nullString2);
// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));
So if you know that fooString1 may be null, tell the reader that by writing
System.out.print(fooString1 != null && fooString1.equals("bar"));
The following are shorter, but it’s less obvious that it checks for null:
System.out.print("bar".equals(fooString1)); // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar")); // Java 7 required
== compares Object references.
.equals() compares String values.
Sometimes == gives illusions of comparing String values, as in following cases:
String a="Test";
String b="Test";
if(a==b) ===> true
This is because when you create any String literal, the JVM first searches for that literal in the String pool, and if it finds a match, that same reference will be given to the new String. Because of this, we get:
(a==b) ===> true
String Pool
b -----------------> "test" <-----------------a
However, == fails in the following case:
String a="test";
String b=new String("test");
if (a==b) ===> false
In this case for new String("test") the statement new String will be created on the heap, and that reference will be given to b, so b will be given a reference on the heap, not in String pool.
Now a is pointing to a String in the String pool while b is pointing to a String on the heap. Because of that we get:
if(a==b) ===> false.
String Pool
"test" <-------------------- a
Heap
"test" <-------------------- b
While .equals() always compares a value of String so it gives true in both cases:
String a="Test";
String b="Test";
if(a.equals(b)) ===> true
String a="test";
String b=new String("test");
if(a.equals(b)) ===> true
So using .equals() is always better.
The == operator checks to see if the two strings are exactly the same object.
The .equals() method will check if the two strings have the same value.
Strings in Java are immutable. That means whenever you try to change/modify the string you get a new instance. You cannot change the original string. This has been done so that these string instances can be cached. A typical program contains a lot of string references and caching these instances can decrease the memory footprint and increase the performance of the program.
When using == operator for string comparison you are not comparing the contents of the string, but are actually comparing the memory address. If they are both equal it will return true and false otherwise. Whereas equals in string compares the string contents.
So the question is if all the strings are cached in the system, how come == returns false whereas equals return true? Well, this is possible. If you make a new string like String str = new String("Testing") you end up creating a new string in the cache even if the cache already contains a string having the same content. In short "MyString" == new String("MyString") will always return false.
Java also talks about the function intern() that can be used on a string to make it part of the cache so "MyString" == new String("MyString").intern() will return true.
Note: == operator is much faster than equals just because you are comparing two memory addresses, but you need to be sure that the code isn't creating new String instances in the code. Otherwise you will encounter bugs.
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true
Make sure you understand why. It's because the == comparison only compares references; the equals() method does a character-by-character comparison of the contents.
When you call new for a and b, each one gets a new reference that points to the "foo" in the string table. The references are different, but the content is the same.
Yea, it's bad...
== means that your two string references are exactly the same object. You may have heard that this is the case because Java keeps sort of a literal table (which it does), but that is not always the case. Some strings are loaded in different ways, constructed from other strings, etc., so you must never assume that two identical strings are stored in the same location.
Equals does the real comparison for you.
Yes, == is bad for comparing Strings (any objects really, unless you know they're canonical). == just compares object references. .equals() tests for equality. For Strings, often they'll be the same but as you've discovered, that's not guaranteed always.
Java have a String pool under which Java manages the memory allocation for the String objects. See String Pools in Java
When you check (compare) two objects using the == operator it compares the address equality into the string-pool. If the two String objects have the same address references then it returns true, otherwise false. But if you want to compare the contents of two String objects then you must override the equals method.
equals is actually the method of the Object class, but it is Overridden into the String class and a new definition is given which compares the contents of object.
Example:
stringObjectOne.equals(stringObjectTwo);
But mind it respects the case of String. If you want case insensitive compare then you must go for the equalsIgnoreCase method of the String class.
Let's See:
String one = "HELLO";
String two = "HELLO";
String three = new String("HELLO");
String four = "hello";
one == two; // TRUE
one == three; // FALSE
one == four; // FALSE
one.equals(two); // TRUE
one.equals(three); // TRUE
one.equals(four); // FALSE
one.equalsIgnoreCase(four); // TRUE
I agree with the answer from zacherates.
But what you can do is to call intern() on your non-literal strings.
From zacherates example:
// ... but they are not the same object
new String("test") == "test" ==> false
If you intern the non-literal String equality is true:
new String("test").intern() == "test" ==> true
== compares object references in Java, and that is no exception for String objects.
For comparing the actual contents of objects (including String), one must use the equals method.
If a comparison of two String objects using == turns out to be true, that is because the String objects were interned, and the Java Virtual Machine is having multiple references point to the same instance of String. One should not expect that comparing one String object containing the same contents as another String object using == to evaluate as true.
.equals() compares the data in a class (assuming the function is implemented).
== compares pointer locations (location of the object in memory).
== returns true if both objects (NOT TALKING ABOUT PRIMITIVES) point to the SAME object instance.
.equals() returns true if the two objects contain the same data equals() Versus == in Java
That may help you.
== performs a reference equality check, whether the 2 objects (strings in this case) refer to the same object in the memory.
The equals() method will check whether the contents or the states of 2 objects are the same.
Obviously == is faster, but will (might) give false results in many cases if you just want to tell if 2 Strings hold the same text.
Definitely the use of the equals() method is recommended.
Don't worry about the performance. Some things to encourage using String.equals():
Implementation of String.equals() first checks for reference equality (using ==), and if the 2 strings are the same by reference, no further calculation is performed!
If the 2 string references are not the same, String.equals() will next check the lengths of the strings. This is also a fast operation because the String class stores the length of the string, no need to count the characters or code points. If the lengths differ, no further check is performed, we know they cannot be equal.
Only if we got this far will the contents of the 2 strings be actually compared, and this will be a short-hand comparison: not all the characters will be compared, if we find a mismatching character (at the same position in the 2 strings), no further characters will be checked.
When all is said and done, even if we have a guarantee that the strings are interns, using the equals() method is still not that overhead that one might think, definitely the recommended way. If you want an efficient reference check, then use enums where it is guaranteed by the language specification and implementation that the same enum value will be the same object (by reference).
If you're like me, when I first started using Java, I wanted to use the "==" operator to test whether two String instances were equal, but for better or worse, that's not the correct way to do it in Java.
In this tutorial I'll demonstrate several different ways to correctly compare Java strings, starting with the approach I use most of the time. At the end of this Java String comparison tutorial I'll also discuss why the "==" operator doesn't work when comparing Java strings.
Option 1: Java String comparison with the equals method
Most of the time (maybe 95% of the time) I compare strings with the equals method of the Java String class, like this:
if (string1.equals(string2))
This String equals method looks at the two Java strings, and if they contain the exact same string of characters, they are considered equal.
Taking a look at a quick String comparison example with the equals method, if the following test were run, the two strings would not be considered equal because the characters are not the exactly the same (the case of the characters is different):
String string1 = "foo";
String string2 = "FOO";
if (string1.equals(string2))
{
// this line will not print because the
// java string equals method returns false:
System.out.println("The two strings are the same.")
}
But, when the two strings contain the exact same string of characters, the equals method will return true, as in this example:
String string1 = "foo";
String string2 = "foo";
// test for equality with the java string equals method
if (string1.equals(string2))
{
// this line WILL print
System.out.println("The two strings are the same.")
}
Option 2: String comparison with the equalsIgnoreCase method
In some string comparison tests you'll want to ignore whether the strings are uppercase or lowercase. When you want to test your strings for equality in this case-insensitive manner, use the equalsIgnoreCase method of the String class, like this:
String string1 = "foo";
String string2 = "FOO";
// java string compare while ignoring case
if (string1.equalsIgnoreCase(string2))
{
// this line WILL print
System.out.println("Ignoring case, the two strings are the same.")
}
Option 3: Java String comparison with the compareTo method
There is also a third, less common way to compare Java strings, and that's with the String class compareTo method. If the two strings are exactly the same, the compareTo method will return a value of 0 (zero). Here's a quick example of what this String comparison approach looks like:
String string1 = "foo bar";
String string2 = "foo bar";
// java string compare example
if (string1.compareTo(string2) == 0)
{
// this line WILL print
System.out.println("The two strings are the same.")
}
While I'm writing about this concept of equality in Java, it's important to note that the Java language includes an equals method in the base Java Object class. Whenever you're creating your own objects and you want to provide a means to see if two instances of your object are "equal", you should override (and implement) this equals method in your class (in the same way the Java language provides this equality/comparison behavior in the String equals method).
You may want to have a look at this ==, .equals(), compareTo(), and compare()
Function:
public float simpleSimilarity(String u, String v) {
String[] a = u.split(" ");
String[] b = v.split(" ");
long correct = 0;
int minLen = Math.min(a.length, b.length);
for (int i = 0; i < minLen; i++) {
String aa = a[i];
String bb = b[i];
int minWordLength = Math.min(aa.length(), bb.length());
for (int j = 0; j < minWordLength; j++) {
if (aa.charAt(j) == bb.charAt(j)) {
correct++;
}
}
}
return (float) (((double) correct) / Math.max(u.length(), v.length()));
}
Test:
String a = "This is the first string.";
String b = "this is not 1st string!";
// for exact string comparison, use .equals
boolean exact = a.equals(b);
// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote
float similarity = simple_similarity(a,b);
The == operator check if the two references point to the same object or not. .equals() check for the actual string content (value).
Note that the .equals() method belongs to class Object (super class of all classes). You need to override it as per you class requirement, but for String it is already implemented, and it checks whether two strings have the same value or not.
Case 1
String s1 = "Stack Overflow";
String s2 = "Stack Overflow";
s1 == s2; //true
s1.equals(s2); //true
Reason: String literals created without null are stored in the String pool in the permgen area of heap. So both s1 and s2 point to same object in the pool.
Case 2
String s1 = new String("Stack Overflow");
String s2 = new String("Stack Overflow");
s1 == s2; //false
s1.equals(s2); //true
Reason: If you create a String object using the new keyword a separate space is allocated to it on the heap.
== compares the reference value of objects whereas the equals() method present in the java.lang.String class compares the contents of the String object (to another object).
I think that when you define a String you define an object. So you need to use .equals(). When you use primitive data types you use == but with String (and any object) you must use .equals().
If the equals() method is present in the java.lang.Object class, and it is expected to check for the equivalence of the state of objects! That means, the contents of the objects. Whereas the == operator is expected to check the actual object instances are same or not.
Example
Consider two different reference variables, str1 and str2:
str1 = new String("abc");
str2 = new String("abc");
If you use the equals()
System.out.println((str1.equals(str2))?"TRUE":"FALSE");
You will get the output as TRUE if you use ==.
System.out.println((str1==str2) ? "TRUE" : "FALSE");
Now you will get the FALSE as output, because both str1 and str2 are pointing to two different objects even though both of them share the same string content. It is because of new String() a new object is created every time.
Operator == is always meant for object reference comparison, whereas the String class .equals() method is overridden for content comparison:
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
All objects are guaranteed to have a .equals() method since Object contains a method, .equals(), that returns a boolean. It is the subclass' job to override this method if a further defining definition is required. Without it (i.e. using ==) only memory addresses are checked between two objects for equality. String overrides this .equals() method and instead of using the memory address it returns the comparison of strings at the character level for equality.
A key note is that strings are stored in one lump pool so once a string is created it is forever stored in a program at the same address. Strings do not change, they are immutable. This is why it is a bad idea to use regular string concatenation if you have a serious of amount of string processing to do. Instead you would use the StringBuilder classes provided. Remember the pointers to this string can change and if you were interested to see if two pointers were the same == would be a fine way to go. Strings themselves do not.
You can also use the compareTo() method to compare two Strings. If the compareTo result is 0, then the two strings are equal, otherwise the strings being compared are not equal.
The == compares the references and does not compare the actual strings. If you did create every string using new String(somestring).intern() then you can use the == operator to compare two strings, otherwise equals() or compareTo methods can only be used.
In Java, when the == operator is used to compare 2 objects, it checks to see if the objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location.
The Java String class actually overrides the default equals() implementation in the Object class – and it overrides the method so that it checks only the values of the strings, not their locations in memory.
This means that if you call the equals() method to compare 2 String objects, then as long as the actual sequence of characters is equal, both objects are considered equal.
The == operator checks if the two strings are exactly the same object.
The .equals() method check if the two strings have the same value.

Duplicate items in Set

In Kotlin, I have a MutableSet of a data class. The data class does not override equals() or hashCode(). I've been encountering bugs involving duplicate objects in the set, and I noticed that calling foo.containsAll(foo) returns false for the set.
I went through each item in the set and only a handful return false for foo.contains(foo.toList()[i]). For those that do, calling foo.toList()[i] == foo.toList()[i] returns true. So, equality checking works.
What is going on here?
I believe the only way this is possible (short of reflection, etc.) is if your data class contains something mutable and an instance changing state after being added to the set, etc. e.g.
data class Foo(var int: Int = 0)
data class Bar(val string: String, val foo: Foo = Foo())
val bars = mutableSetOf<Bar>()
bars += Bar("")
bars += Bar("")
println(bars.containsAll(bars)) // true
bars.first().foo.int = 12
println(bars.containsAll(bars)) // false
This is because the result of hashCode() is being used in the set to identify it but if the state changes in an instance of your data class then it will likely have a different hash value causing issues like this.
In general elements in sets and keys in maps should be immutable to avoid this issue.

Passing strings as task creation discriminants in Ada

I'm moving my first steps with Ada, and I'm finding that I struggle to understand how to do common, even banal, operations that in other languages would be immediate.
In this case, I defined the following task type (and access type so I can create new instances):
task type Passenger(
Name : String_Ref;
Workplace_Station : String_Ref;
Home_Station : String_Ref
);
type Passenger_Ref is access all Passenger;
As you can see, it's a simple task that has 3 discriminants that can be passed to it when creating an instance. String_Ref is defined as:
type String_Ref is access all String;
and I use it because apparently you cannot use "normal" types as task discriminants, only references or primitive types.
So I want to create an instance of such a task, but whatever I do, I get an error. I cannot pass the strings directly by simply doing:
Passenger1 := new Passenger(Name => "foo", Workplace_Station => "man", Home_Station => "bar");
Because those are strings and not references to strings, fair enough.
So I tried:
task body Some_Task_That_Tries_To_Use_Passenger is
Passenger1 : Passenger_Ref;
Name1 : aliased String := "Foo";
Home1 : aliased String := "Man";
Work1 : aliased String := "Bar";
begin
Passenger1 := new Passenger(Name => Name1'Access, Workplace_Station => Work1'Access, Home_Station => Home1'Access);
But this doesn't work either, as, from what I understand, the Home1/Name1/Work1 variables are local to task Some_Task_That_Tries_To_Use_Passenger and so cannot be used by Passenger's "constructor".
I don't understand how I have to do it to be honest. I've used several programming languages in the past, but I never had so much trouble passing a simple String to a constructor, I feel like a total idiot but I don't understand why such a common operation would be so complicated, I'm sure I'm approaching the problem incorrectly, please enlighten me and show me the proper way to do this, because I'm going crazy :D
Yes, I agree it is a serious problem with the language that discriminates of task and record types have to be discrete. Fortunately there is a simple solution for task types -- the data can be passed via an "entry" point.
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is
task type Task_Passenger is
entry Construct(Name, Workplace, Home : in String);
end Passenger;
task body Task_Passenger is
N, W, H : Unbounded_String;
begin
accept Construct(Name, Workplace, Home : in String) do
N := To_Unbounded_String(Name);
W := To_Unbounded_String(Workplace);
H := To_Unbounded_String(Home);
end Construct;
--...
end Passenger;
Passenger : Task_Passenger;
begin
Passenger.Construct("Any", "length", "strings!");
--...
end Main;
Ada doesn't really have constructors. In other languages, a constructor is, in essence, a method that takes parameters and has a body that does stuff with those parameters. Trying to get discriminants to serve as a constructor doesn't work well, since there's no subprogram body to do anything with the discriminants. Maybe it looks like it should, because the syntax involves a type followed by a list of discriminant values in parentheses and separated by commas. But that's a superficial similarity. The purpose of discriminants isn't to emulate constructors.
For a "normal" record type, the best substitute for a constructor is a function that returns an object of the type. (Think of this as similar to using a static "factory method" instead of a constructor in a language like Java.) The function can take String parameters or parameters of any other type.
For a task type, it's a little trickier, but you can write a function that returns an access to a task.
type Passenger_Acc is access all Passenger;
function Make_Passenger (Name : String;
Workplace_Station : String;
Home_Station : String) return Passenger_Acc;
To implement it, you'll need to define an entry in the Passenger task (see Roger Wilco's answer), and then you can use it in the body:
function Make_Passenger (Name : String;
Workplace_Station : String;
Home_Station : String) return Passenger_Acc is
Result : Passenger_Acc;
begin
Result := new Passenger;
Result.Construct (Name, Workplace_Station, Home_Station);
return Result;
end Make_Passenger;
(You have to do this by returning a task access. I don't think you can get the function to return a task itself, because you'd have to use an extended return to set up the task object and the task object isn't activated until after the function returns and thus can't accept an entry.)
You say
"I don't understand how I have to do it to be honest. I've used several programming languages in the past, but I never had so much trouble passing a simple String to a constructor, I feel like a total idiot but I don't understand why such a common operation would be so complicated, I'm sure I'm approaching the problem incorrectly, please enlighten me and show me the proper way to do this, because I'm going crazy :D"
Ada's access types are often a source of confusion. The main issue is that Ada doesn't have automatic garbage collection, and wants to ensure you can't suffer from the problem of returning pointers to local variables. The combination of these two results in a curious set of rules that force you to design your solution carefully.
If you are sure your code is good, then you can always used 'Unrestricted_Access on an aliased String. This puts all the responsibility on you to ensure the accessed variable won't disappear from underneath the task though.
It doesn't have to be all that complicated. You can use an anonymous access type and allocate the strings on demand, but please consider if you really want the strings to be discriminants.
Here is a complete, working example:
with Ada.Text_IO;
procedure String_Discriminants is
task type Demo (Name : not null access String);
task body Demo is
begin
Ada.Text_IO.Put_Line ("Demo task named """ & Name.all & """.");
exception
when others =>
Ada.Text_IO.Put_Line ("Demo task terminated by an exception.");
end Demo;
Run_Demo : Demo (new String'("example 1"));
Second_Demo : Demo (new String'("example 2"));
begin
null;
end String_Discriminants;
Another option is to declare the strings as aliased constants in a library level package, but then you are quite close to just having an enumerated discriminant, and should consider that option carefully before discarding it.
I think another solution would be the following:
task body Some_Task_That_Tries_To_Use_Passenger is
Name1 : aliased String := "Foo";
Home1 : aliased String := "Man";
Work1 : aliased String := "Bar";
Passenger1 : aliased Passenger(
Name => Name1'Access,
Workplace_Station => Work1'Access,
Home_Station => Home1'Access
);
begin
--...

Ordering using a declared variable's property

I have a ScInfo class that exists in many different classes. This class also has a list of ScDetails which has a Date member variable called nextExecution.
I need to continuously look up eligible objects with their ScDetails object's nextExecution member variable is after or equal to the current server's time (i.e. persistenceManagerInstance.getServerDate()). Meaning that I need to look up objects, with ScInfo having a ScDetails object with nextExecution >= serverDate)
So I use the following method (A portion is shown):
public List<Object[]> getEligbleForExecution(long amount) {
PersistenceManager pm = null;
Transaction t = null;
try {
pm = getPM();
t = pm.currentTransaction();
t.begin();
Query q = pm
.newQuery(
entityClass, //This is generic
"!this.deleted && this.scheduleActive && det.active == true && (det.nextExecution == null || det.nextExecution <= :serverDate) && det.running == false && this.scInfo.scDetails.contains(det)");
q.declareVariables(ScDetail.class.getName() + " det;");
q.setRange(0, amount);
q.setResult("this, det");
q.setOrdering("det.nextExecution"); // This is the statement I need to apply but it's causing the error below
Date serverDate = pm.getServerDate();
List<Object[]> raw = new ArrayList<Object[]>((List<Object[]>) q.execute(serverDate));
Which throws the following error stack trace (DEBUG level, I mentioned what I thought to be essential for solving this problem):
14:54:32 DEBUG (Log4JLogger.java:58)-[main] >> QueryToSQL.processVariable (unbound) variable=det is not yet bound so returning UnboundExpression
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Updating mapping of org.datanucleus.store.rdbms.sql.expression.NullLiteral#727f3b8a to be org.datanucleus.store.mapped.mapping.DateMapping#e72a8082
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Transaction rolling back for ObjectManager org.datanucleus.MultithreadedObjectManager#fba0f36
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Rolling back [DataNucleus Transaction, ID=Xid={A strange uncopyable character is in here !}, enlisted resources=[]]
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Transaction rolled back in 1 ms
14:54:32 ERROR (ScTasksDAOImpl.java:67)-[main] Looking up eligible SC tasks
java.lang.NullPointerException
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.processVariableExpression(QueryToSQLMapper.java:3245)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.processPrimaryExpression(QueryToSQLMapper.java:2075)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compilePrimaryExpression(AbstractExpressionEvaluator.java:180)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileUnaryExpression(AbstractExpressionEvaluator.java:169)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileAdditiveMultiplicativeExpression(AbstractExpressionEvaluator.java:148)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileRelationalExpression(AbstractExpressionEvaluator.java:123)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.compileOrAndExpression(AbstractExpressionEvaluator.java:65)
at org.datanucleus.query.evaluator.AbstractExpressionEvaluator.evaluate(AbstractExpressionEvaluator.java:46)
at org.datanucleus.query.expression.Expression.evaluate(Expression.java:337)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.compileOrdering(QueryToSQLMapper.java:845)
at org.datanucleus.store.rdbms.query.QueryToSQLMapper.compile(QueryToSQLMapper.java:403)
at org.datanucleus.store.rdbms.query.JDOQLQuery.compileQueryFull(JDOQLQuery.java:883)
at org.datanucleus.store.rdbms.query.JDOQLQuery.compileInternal(JDOQLQuery.java:343)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1747)
at org.datanucleus.store.query.Query.executeWithArray(Query.java:1666)
at org.datanucleus.api.jdo.JDOQuery.execute(JDOQuery.java:243)
at com.sc.ipk.sc.services.ScTasksDAOImpl.getEligbleForExecution(ScTasksDAOImpl.java:41)
at com.sc.ipk.ixl.services.IxlTestDAOImpl.main(IxlTestDAOImpl.java:977)
14:54:32 DEBUG (Log4JLogger.java:58)-[main] Object Manager "org.datanucleus.MultithreadedObjectManager#fba0f36" closed
So is it not possible to use declared variables to query ordering ? I tried using sub-queries but I couldn't get that to work either, may be I can start a new question for that, if ordering using declared variables isn't possible.
EDIT:
Neil generously suggested that ordering based on an element that should exist in a collection doesn't look reasonable to him. I understand that but I cannot for example look-up ScDetails objects first after ordering them of course and then look-up my main objects afterwards because my target main object may differ from time to time and I may look-up ScDetails objects that doesn't belong to the main candidate class.
For example:
A has ScInfo which has a collection of ScDetails
B, C (Same as above)
So if I lookup ScDetails objects first (After ordering an all), I cannot filter my main candidate classes (A, B & C) because I may use a ScDetails that belongs to A while I'm trying to get B or C candidates.
Thank you.
I don't see how you can order by that variable. It represents an element of a collection of the candidate. Consequently if a candidate has say 5 elements then it is indeterminate how it can order by some property on the element (1-N mapping). Obviously if the candidate was the element then ordering by some property of the element makes perfect sense, whether variable or not.

Resources