Odd value returned by simple Fortran function - dll

Just as a forward, I am a complete beginner when it comes to Fortran. I've spent quite awhile looking at the other questions on SO, but I couldn't identify a similar question to this, so please forgive me if my solution is either obvious, or already been answered :)
I'm attempting to learn how to correctly implement a self-written Fortran DLL in a VB.net application. I've been able to have VB recognize the DLL, and execute the function without any errors. The error comes rather as expected output compared to actual output.
My Fortran DLL function reads as follows:
function ex(i)
integer*4 i
ex=i+1
return
end
A very simple function that increments the passed parameter by one and returns the value. (I think). The VB Application has the following code.
<DllImport("ex.dll")> _
Public Shared Function ex(ByRef val As Integer) As Integer
End Function
Private Sub btn_Fortran_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Fortran.Click
Console.WriteLine(ex(1))
End Sub
So, I'm passing the ex function the integer value 1. So I would expect the value 2 to be written to the console. Instead, I get the value "1073741824" Not exactly equal. Any ideas where I'm obviously falling short?

Learning a language in a mixed language content is "a hard row to hoe". Note that value you obtained is 2**30.
In the fortran portion, you should also declare the return value of the function: "integer*4 function ex (i)" is the old fashioned way. You are probably getting ex as a real through implicit typing. It is a very good idea to include "implicit none" in all of your programs and procedures to prevent implicit typing. Many compilers include an option for the same purpose.
Late edit:
Here is a program that demonstrates what was happening by showing what value is obtained when the bit-pattern real value 2.0 is interpreted as an integer. First the program equates a real and an integer. In this case the compiler "knows" about the types and converts the value. In the second case the raw bit pattern is transferred without being converted.
program test_tc
real :: my_real
integer :: my_int
my_real = 2.0
my_int = my_real
write (*, *) my_int
my_int = transfer ( my_real, my_int )
write (*, *) my_int
end program test_tc
Output is:
2
1073741824

It appears that I was nearly on the right track, but the way in which I declared 'i' made some weird things happen. When using the following convention of
integer*4 :: ex, i
The function returns the correct value. So, my function looks like this
function ex(i)
integer*4 :: ex, i
ex=i+1
return
end function
Thanks both of you for the help. I upvoted both of you for simply opening my eyes to some aspect of the language I didn't fully understand beforehand.

Related

IsNumeric() allowing minus at last of the values

I am using IsNumeric() function in my code to validate numbers.
IsNumeric(100) - true,
IsNumeric(-100) - true,
IsNumeric(+100) - true,
IsNumeric(100-) - true - I have doubt in this. (100-) Is this a valid number? IsNumeric () returns true to this value.
Dim latitude As String = "12.56346-"
If IsNumeric(latitude) Then
If (Convert.ToDouble(latitude) >= -90 And Convert.ToDouble(latitude) <= 90) Then
isValidLatitude.Text = "true"
Else
isValidLatitude.Text = "false"
End If
Else
isValidLatitude.Text = "false"
End If
Error while converting latitude to double
Input string was not in a correct format.
IsNumeric is from the Microsoft.VisualBasic namespace/dll, a bunch of helper stuff intended to help VB6 programmers get their arcane VB6 code /knowledge working on VB.NET
You'll note if you use other functions from the same dll such as Microsoft.VisualBasic.Conversion.Int(), or you use dedicated VB.NET converters such as CInt or CDbl these will also cope with a trailing minus sign and return a negative value
If you want to dispense with the old ways of VB6, use a numeric type's TryParse.. but all in, be consistent / if you use a function from Microsoft.VisualBasic to determine if a conversion can be made, use the vb conversion because within itself the package will be consistent but between Microsoft.VB and normal .net System there are some differences in behavior
Edit:
A couple of people have been wondering about the source code and how it uses TryParse, so why doesn't it work like using TryParse directly?
Microsoft.VisualBasic.Information.IsNumeric() uses Microsoft.VisualBasic.CompilerServices.DoubleType.TryParse() to determine whether an expression is numeric. This DoubleType.TryParse is not the same as Double.TryParse - it is a helper method again in the VB namespace that specifically sets the NumberStyles.AllowTrailingSign flag among many other flags. When parsing the number (first as non currency related, using Double.Parse, then if it fails a second attempt is made using adjusted values for currency related tests) this AllowTrailingSign flag will be considered in conjunction with other regional number formatting rules in determining if the passed in value is numeric
You'll note that on a machine obeying a USA number formatting culture, a string of "(100$)" is also declared to be numeric but calling Double.TryParse("(100$)", x) will also return false. The VB helper methods here are being a lot more liberal in what they accept than the System methods, because they're telling the System methods to be more liberal than they are by default
As noted, I've always regarded the Microsoft.VisualBasic namespace as a bunch of helper methods intended to allow terrible old VB6 code to be pasted into VB.NET and work with minimal fiddling. I wouldn't advocate using it for new projects and I remove the reference when I work on VB.NET - using it to support the VB6 notions of "just sling anything in, of any type, and it'll probably figure it out and work.. and if it doesn't we can always on error resume next" should be discarded in favour of precise and accurate about the operations executed and their intent
Note: my previous answers were wrong about assuming it was a bug. As the answer of #Damien_The_Unbeliever states, this function tries to validate the string as a lot of data types. And actually, the value "100-" is a valid Decimal number. That's why it returns true (as it's a "valid" Decimal) but gives a exception when converting to Double (as it's not a valid Double). #Damien_The_Unbeliever really deserves your +1 for pointing that.
From the documentation (showing all the data types that IsNumeric tries to validate):
IsNumeric returns True if the data type of Expression is Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong, or UShort. It also returns True if Expression is a Char, String, or Object that can be successfully converted to a number. Expression can contain non-numeric characters. IsNumeric returns True if Expression is a string that contains a valid hexadecimal or octal number. IsNumeric also returns True if Expression contains a valid numeric expression that begins with a + or - character or contains commas.
Also, #CaiusJard did a nice search and pointed out that inner methods use a NumberStyles.AllowTrailingSign option, which allows this behavior.
Ok, now to the solution:
Just use a TryParse method, from your desired data type (int, long, etc...). The cool thing is that it'll behaves exactly as you expect, and if the parsing is successful, we have the parsed value already available to use!
if (Int32.TryParse(value, out int number))
{
// String is a valid number, and is already parsed in the 'number' variable!
}
else
{
// String is not a valid number!
}
Solution's VB.Net version:
Dim value As String = "12.56346-"
Dim number As Double = 0
If Double.TryParse(value, number) Then
' String is a valid number, and is already parsed in the "number" variable!
isValidLatitude.Text = "true"
Else
' String is not a valid number!
isValidLatitude.Text = "false"
End If
IsNumeric answers a question no sane person wants to ask. As quoted by Vitox's answer:
IsNumeric returns True if the data type of Expression is Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong, or UShort. It also returns True if Expression is a Char, String, or Object that can be successfully converted to a number.
Note, it doesn't tell you that the given string can be converted to all numeric types. It tells you that the string can be converted to at least one numeric type. And for bonus bad style points, of course, it doesn't tell you which types the string can be converted to.
Decimal.Parse("100-") will execute perfectly well and give you a Decimal containing a value of -100.
So, it's not a bug, it's a bad function that has been retained for backwards compatibility reasons. Nowadays, we know better, and that we want to test whether a string can be converted to a specific data type, for which the TryParse family of functions have been designed.

VB.Net: "Nice", maintainable way of matching integer error code to error strings for UI

I'm building a user interface (HMI, human-machine interface) for a machine that does various motion-controlled tasks. The motion controller is a bit on the primitive side in terms of programming, and so I have it sending me error and status codes in the form of integers.
As an example: I have a box that indicates what stage the machine is at during its autocycle. The machine sends a '1', and I want the box to say 'Waiting to start autocycle.' Here are a few more:
1 - Waiting to start autocycle.
2 - Returning to home.
3 - Waiting at home.
4 - Tracking encoder A.
5 - Tracking encoder B.
And so on. Is there a clean way to maintain these messages in VB.net using, say, resources, that I don't know about, or should I just make an XML file that just contains something like
<statusmessage code="1" message="Waiting to start autocycle.">
and read that in when the program starts?
My current method is a hard-coded select statement with the strings in the actual VB source so you have to recompile the program if you want to change a message (gross).
If it's relevant, this program is never going to be multi-language.
Thanks for any advice!
It's easy to do this with an .xml file. That or some similar file format would be my preference. Some people would prefer using app.config or file format. When I evaluate something like this, simplicity of maintenance is probably the highest priority, and there are several methods that would work equally well in this regard. A database table could be used, but it seems like an overcomplication.
If you don't need to worry about multiple languages, it is possible to do this...
Public Enum Foo
<Description("Waiting to start autocycle")> WaitingToStartAutoCycle = 1
<Description("Returning to home")> ReturningToHome = 2
' [ etc...]
End Enum
You can then use reflection to get the description. This is ripped out of a larger piece of code, so forgive me if I miss part of it..
Public Function GetEnumDescription(ByVal value As Object) As String
Dim type As Type = value.GetType()
' Excersize for the reader, validate that type is actually an Enum
Dim f As FieldInfo = type.GetField(value.ToString)
If f IsNot Nothing Then
Dim ca() As Object = f.GetCustomAttributes(GetType(DescriptionAttribute), False)
If ca IsNot Nothing AndAlso ca.Length > 0 Then
Return CType(ca(0), DescriptionAttribute).Description
End If
End If
Return value.ToString ' Last resort if no Description attribute
End Function

Using := in a vba function call

I am wondering what the reason is for using := in a function call. I know := is used when a function calls for multiple criteria. You can use the := to denote which criteria you are referring to. However, I do not understand the following snippets. This is from http://www.cpearson.com/excel/PassingAndReturningArrays.htm.
Sub AAATest()
Dim StaticArray(1 To 3) As Long
Dim N As Long
StaticArray(1) = 1
StaticArray(2) = 2
StaticArray(3) = 3
PopulatePassedArray Arr:=StaticArray
For N = LBound(StaticArray) To UBound(StaticArray)
Debug.Print StaticArray(N)
Next N
End Sub
He is using Arr:=StaticArray. What is the Arr:= used for?
My second example is as follows:
If IsArrayAllocated(Arr:=Arr) = True Then
If NumberOfArrayDimensions(Arr:=Arr) = 1 Then
He is passing Arr to IsArrayAllocated but I do not understand why he can't just use IsArrayAllocated(Arr) instead. Thanks for any insight on this.
FOR READABILITY
"NumberOfArrayDimensions" is a function itself, which has an "Arr:= argument itself.
If NumberOfArrayDimensions(Arr:=Arr) = 1 then
You would use ":=" in the absence of multiple arguments purely for readability.
Examples:
A function call written as
HireEmployees NumberOfSalesmanToHire:=4
Is much more readable than a cryptic
HireEmployees nbSlms:=4
Or the even more cryptic
HireEmployees 4
You'll write your code 1time, but you'll have to read it many, many more times.
To that end, it's great to always understand what you are reading as fast as possible.
On a side note, I prefer not to use abbreviations like "Arr".
Is it short for an Array or was it written on Pirate Day?
I prefer to make sure everything is explicit since it doesn't lower the performance of the computation anyway
EDIT
FOR MAINTENANCE
You might also wish to use the ":=" in function calls for maintenance.
Let's say you have this :
Sub HireEmployees(Optional NumberOfSalesmanToHire as Integer=1, Optional NumberOfJanitors as Integer = 0)
(do something with Salesman)
(do something with Janitors)
End Sub
Later, you change this code so it doesn't have Salesman anymore:
Sub HireEmployees(Optional NumberOfJanitors as Integer = 0)
(do something with Janitors)
End Sub
Now, if your arguments were not explicit, you'd start having funky behaviors through-out your code:
HireEmployees 4
What did the previous dev mean? Was it the old Salesman call or was this changed to now only work with janitors...? Who knows.
You don't have that problem if your calls were explicit:
HireEmployees NumberOfSalesman:=4
As the compiler will now warn you that this doesn't work anymore, therefor preventing your code from interpreting old Salesman as Janitors.

undocumented vba special keywords - Circle and Scale

The VBA documentation defines the following token:
special-form = “Array“ / “Circle” / “Input” / “InputB” / “LBound” / “Scale” / “UBound”
According to the documemtation:
A special-form is a reserved-identifier that is used in an expression as if it was a program defined procedure name but which has special syntactic rules for its argument.
But there is no mention of the purpose of these keywords, nor there number, type of parameters and return values.
Some are documented in other places:
Array returns a literal array with an variable number of parameters
Input and InputB are used with line
LBound and Ubound returns respectively tho first and last index of an array, same as VB
My question is:
What is the purpose of Circle and Scale and how are they used ?
I found the correct (odd) syntax of Circle which is the same as the BASIC statement
CIRCLE(xcenter, ycenter), radius[,[color][,[start],[end][,aspect]]]
and gives no syntax error (I didn't find any mention of Scale though it doesn't seem to have any parameters) but I can't assign it to a variable, and if I try to run the code below (which is syntaxically correct) I get the following error:
Method not valid without suitable object
code:
Sub test1()
Circle (5, 5), 10
End Sub
Sub test2()
Scale
End Sub
VB inherited the odd syntax of graphics methods (what circle/scale are) from QBASIC and VBA further inherited them from VB (upon which it is based). Presumably it was decided that rather than removing the special parsing rules for these constructs in the runtime, it was simpler to leave them as a noop.
CREDIT TO Alex K. (see his comment)

When does = perform comparison instead of assignment?

In VB.NET, there's no == operator for comparison, so the = operator serves that purpose as well as assignment. I have a function, and I want it to return the boolean result of a comparison, without storing that result in a variable:
Private Function foo() As Boolean
Dim bar As Integer = 1
Return bar = 2
End Function
Returns: False
OK, but what's the value of bar?
Private Function foo() As KeyValuePair(Of Boolean, Integer)
Dim bar As Integer = 1
Return New KeyValuePair(Of Boolean, Integer)(bar = 2, bar)
End Function
Returns: False, 1
It looks like = will perform a comparison when the statement context demands it, but is this guaranteed? That is, can I be sure that bar will never be set to 2 in this situation?
Also, I know that VB.NET doesn't allow chained inline assignments, which may be for the best. Does this odd = behavior cause any other quirks I should be aware of?
You cannot do in-line assignments in VB, Assignment is an explicit statement:
[Let] <<target-reference>> = <<value-expression>>
The Let is optional and implicit, and hardly ever used anymore. The general rule that you can use to distinguish the [Let] command from equality testing is that for Let, no other keyword may come before the target-reference in the statement. AFAIK, in all cases of = as equality testing, there is one or more other keywords that precede it in the statement.
In your first example, the keyword Return precedes your =, so it's an equality test, and not an assignment.
In your first example you can do either:
Return 2
or
bar = 2
Return bar
As for your question "OK, but what's the value of bar?", bar still equals one.
= in VB cause no quirks. It works exactly as documented, and it always has (including its predecessor, BASIC back to 1968).
If you are starting to code in VB (coming from a language like C#), you should start getting used to the peculiar VB way of doing things; which is based on the idea: as simple and intuitive for the programmer as possible. "If assignation and comparison happen always in different contexts, why not using the same operator and let the context define its exact meaning?" -> VB-way of seeing things. "No, different realities have to be accounted for by different operators. End of the discussion" -> C#-way. :)
Is this reliable? Can you blindly trust on these not-always-clear-for-a-programmer bits? Sure, VB.NET peculiarities are highly-reliable and trustworthy. You can always use = (or Is on some contexts, but VS would tell you) and be completely sure that the code will do what is expected. But the question is: are you sure that you write exactly what you want?
This last question is what, perhaps, is more criticable of VB and what might give some problems to programmers from other languages: the higher the flexibility, the more likely is that you make an error; mainly if you are used to a different format.
Regarding the chained inline assignments, I honestly don't see its true utility (and never use them in C#). Regarding other differences with respect to C#, there are plenty of them; in some cases, I think that the C# approach is better; other times, the VB.NET one. On readability/length of code, I can refer to the With Statement I have always found somehow useful which is not present in C#.
One way to have 100% sure that the expression will be evaluated as an boolean expression is to use ()
e.g
Dim a = 2
Return (a = 1)
Since you cannot set a value to a variable wihtin the parenthesis.
What i want to say is: on an return statament for example you cant assing a value to a variable so, even if you use
a = 1
The compilator knows that this expression only can be an boolean expression.
The same to the if statament and so on..
Heh back in QB45 days we used to exploit the fact that "True" was the numeric value -1. So you would see code like x = 1 - x * (x < 6) (translation: increment x, but reset to 1 when it gets to 6)