I was told a long time ago that in FORTRAN, everything is passed by value. Therefore I would need to do this (provided mySubroutine is suitably defined elsewhere):
double precision :: myArray(2)
myArray(1:2) = (/ 2.3d0, 1.5d0 /)
CALL mySubroutine(myArray)
However, I also found that the program compiles and runs as expected if I do this
CALL mySubroutine((/ 2.3d0, 1.5d0 /))
without needing to define an intermediary array myArray. I thought that I was passing myArray into mySubroutine by reference. What is going on under the hood in the second version? Is the compiler unpacking the subroutine call, declaring a temporary variable only to pass it by reference?
To a large extent, trying to classify Fortran procedure calling with pass-by-reference and pass-by-value is not too helpful. You can find more detail on that in response to questions like this one and this one.
In short, generally procedure references are such that changes to a variable in a procedure are reflected in the variable where the procedure was referenced. In some cases a compiler may choose to do copy-in/copy-out, and in others it effectively must. Equally, the value attribute of a dummy argument specifies that an anonymous copy be made.
Where this question adds something a little different is in the use of an expression such as in
call mySubroutine([2.3d0, 1.5d0]) ! Using F2003 array constructor syntax
Is the compiler creating a temporary variable?
Admittedly, this is perhaps just a looseness in terminology but it's worth saying that there is certainly no variable involved. [2.3d0, 1.5d0] is an expression, not a variable. Crucially this means that it cannot be modified (appear in a variable definition context) in the procedure. Restrictions that apply in the case using an expression rather than a (temporary) variable include:
the dummy argument associated with an expression may not have the intent(inout) or the intent(out) attribute;
if the dummy argument hasn't an intent attribute then that argument may not be modified if the associated actual argument is an expression.
Now, if the dummy argument has the value attribute the effect of the procedure is the same whichever way it is referenced.
To conclude, the program may work just as well with an expression instead of an intermediate variable. If it doesn't that's because of violation of some aspect of Fortran. How it works is a problem for the compiler not the programmer.
Related
"What are explicit declaration & implicit declaration of variables in programming language concepts and their advantages and disadvantages?"
An explicit declaration is when you start making the variable by order it first.
ex: String name; name="yourname";
the advantages is you be able to fill your variable with any algorithm or math logic to make a value. the disadvantages is when you use it as a material without fill the value of your variable ,there will be an error.
An implicit declaration is when you make a variable directly without order it first. ex : String name="yourname";
the advantages : it is a practically treatment at some condition.
.
Explicit means declaring variable like in c.
Implicit declaration in variable declaration in python.
In Explicit we should cast.
In implicit no need of casting.
Explicit variable declaration means that the type of the variable is declared before or when the variable is set. Implicit variable declaration means the type of the variable is assumed by the operators, but any data can be put in it.
In C,
int x = 5; printf(x-5); x = "test"; printf(x-5);
returns a compile time error when you set x to test
but in Python,
x = 5; print(x-5); x = "test"; print(x-5);
will "compile" (python doesn't compile, but it will run the program) and give you a runt time error when you try to subtract from the string.
One advantage of Implicit variables is that it makes it easier to write code without worrying about the behind the scenes data type, the compiler should pick the appropriate one based on its future usage.
Another advantage is that you can flexibly type a variable to hold different things that may not even share a parent class. Doing this is risky, as you have no guarantees that the objects will be interpreted correctly by following code.
One disadvantage is that Implicit variables have no guarantees of what they are. A function that computes the difference between two numbers will not return an compile time error if the variables have strings in them. You passed in two variables, it is up to you to ensure they are the right type. It also makes reading code harder in some ways. var nextLocation = LeftHandedSmokeShifter(3.3) is completely legitimate code, but You have to look up the function to even guess what it is doing. string nextLocation = LeftHandedSmokeShifter(3.3) at least tells me that I should be using the output for mathematical operations.
Type heavy languages are always explicitly declared and typed, but type weak languages are mostly implicitly typed. If you can set a variable to "Var" it is likely an implicitly typed language.
I try to create a c++ flex/bison parser. I used this tutorial as a starting point and did not change any bison/flex configurations. I am stuck now to the point of trying to unit test the lexer.
I have a function in my unit tests that directly calls yylex, and checks the result of it:
private: static void checkIntToken(MyScanner &scanner, Compiler *comp, unsigned long expected, unsigned char size, char isUnsigned, unsigned int line, const std::string &label) {
yy::MyParser::location_type loc;
yy::MyParser::semantic_type semantic; // <---- is seems like the destructor of this variable causes the crash
int type = scanner.yylex(&semantic, &loc, comp);
Assert::equals(yy::MyParser::token::INT, type, label + "__1");
MyIntToken* token = semantic.as<MyIntToken*>();
Assert::equals(expected, token->value, label + "__2");
Assert::equals(size, token->size, label + "__3");
Assert::equals(isUnsigned, token->isUnsigned, label + "__4");
Assert::equals(line, loc.begin.line, label + "__5");
//execution comes to this point, and then, program crashes
}
The error message is:
program: ../src/__autoGenerated__/MyParser.tab.hh:190: yy::variant<32>::~variant() [S = 32]: Assertion `!yytypeid_' failed.
I have tried to follow the logic in the auto-generated bison files, and make some sense out of it. But I did not succeed on that and ultimately gave up. I searched then for any advice on the web about this error message but did not find any.
The location indicated by the error has the following code:
~variant (){
YYASSERT (!yytypeid_);
}
EDIT: The problem disappears only if I remove the
%define parse.assert
option from the bison file. But I am not sure if this is a good idea...
What is the proper way to obtain the value of the token generated by flex, for unit testing purposes?
Note: I've tried to explain bison variant types to the best of my knowledge. I hope it is accurate but I haven't used them aside from some toy experiments. It would be an error to assume that this explanation in any way implies an endorsement of the interface.
The so-called "variant" type provided by bison's C++ interface is not a general-purpose variant type. That was a deliberate decision based on the fact that the parser is always able to figure out the semantic type associated with a semantic value on the parser stack. (This fact also allows a C union to be used safely within the parser.) Recording type information within the "variant" would therefore be redundant. So they don't. In that sense, it is not really a discriminated union, despite what one might expect of a type named "variant".
(The bison variant type is a template with an integer (non-type) template argument. That argument is the size in bytes of the largest type which is allowed in the variant; it does not in any other way specify the possible types. The semantic_type alias serves to ensure that the same template argument is used for every bison variant object in the parser code.)
Because it is not a discriminated union, its destructor cannot destruct the current value; it has no way to know how to do that.
This design decision is actually mentioned in the (lamentably insufficient) documentation for the Bison "variant" type. (When reading this, remember that it was originally written before std::variant existed. These days, it would be std::variant which was being rejected as "redundant", although it is also possible that the existence of std::variant might have had the happy result of revisiting this design decision). In the chapter on C++ Variant Types, we read:
Warning: We do not use Boost.Variant, for two reasons. First, it appeared unacceptable to require Boost on the user’s machine (i.e., the machine on which the generated parser will be compiled, not the machine on which bison was run). Second, for each possible semantic value, Boost.Variant not only stores the value, but also a tag specifying its type. But the parser already “knows” the type of the semantic value, so that would be duplicating the information.
Therefore we developed light-weight variants whose type tag is external (so they are really like unions for C++ actually).
And indeed they are. So any use of a bison "variant" must have a definite type:
You can build a variant with an argument of the type to build. (This is the only case where you don't need a template parameter, because the type is deduced from the argument. You would have to use an explicit template parameter only if the argument were not of the precise type; for example, an integer of lesser rank.)
You can get a reference to the value of known type T with as<T>. (This is undefined behaviour if the value has a different type.)
You can destruct the value of known type T with destroy<T>.
You can copy or move the value from another variant of known type T with copy<T> or move<T>. (move<T> involves constructing and then destructing a T(), so you might not want to do it if T had an expensive default constructor. On the whole, I'm not convinced by the semantics of the move method. And its name conflicts semantically with std::move, but again it came first.)
You can swap the values of two variants which both have the same known type T with swap<T>.
Now, the generated parser understands all these restrictions, and it always knows the real types of the "variants" it has at its disposal. But you might come along and try to do something with one of these objects in a way that violates a constraint. Since the object really doesn't have any way to check the constraint, you'll end up with undefined behaviour which will probably have some disastrous eventual consequence.
So they also implemented an option which allows the "variant" to check the constraints. Unsurprisingly, this consists of adding a discriminator. But since the discriminator is only used to validate and not to modify behaviour, it is not a small integer which chooses between a small number of known alternatives, but rather a pointer to a std::typeid (or NULL if the variant does not yet contain a value.) (To be fair, in most cases alignment constraints mean that using a pointer for this purpose is no more expensive than using a small enum. All the same...)
So that's what you're running into. You enabled assertions with %define parse.assert; that option was provided specifically to prevent you from doing what you are trying to do, which is let the variant object's destructor run before the variant's value is explicitly destructed.
So the "correct" way to avoid the problem is to insert an explicit call at the end of the scope:
// execution comes to this point, and then, without the following
// call, the program will fail on an assertion
semantic.destroy<MyIntType*>();
}
With the parse assertion enabled, the variant object will be able to verify that the types specified as template parameters to semantic.as<T> and semantic.destroy<T> are the same types as the value stored in the object. (Without parse.assert, that too is your responsibility.)
Warning: opinion follows.
In case anyone reading this cares, my preference for using real std::variant types comes from the fact that it is actually quite common for the semantic value of an AST node to require a discriminated union. The usual solution (in C++) is to construct a type hierarchy which is, in some ways, entirely artificial, and it is quite possible that std::variant can better express the semantics.
In practice, I use the C interface and my own discriminated union implementation.
If I call my function like this:
t = calcMonth(month)
and the corresponding function is
real function calcMonth(m)
real b, m
b = 10
calcMonth = b*m
Does my variable m get overwritten to garbage value?
Responding to your comment
i thought by declaring the variable 'm' locally it gets rid of the passed value of 'm'
When you say (cut down for clarity)
real function calcMonth(m)
real m
end function
you are not declaring a local variable m in the function. Instead you are declaring the type of the dummy argument m. Indeed, doing this declaration is the only sane way to declare types and attributes of dummy arguments. [Discussion of sanity outside the scope of this answer.]
Whilst reusing an identifier for a local variable can obscure other externally defined objects, it simply isn't allowed for dummy arguments.
I'd be very scared of a language tutorial which didn't make these features clear, but I'll speculate as to why there may be some confusion.
It may be that when one has
real function calcMonth(m)
calcMonth = 10*m ! Oh look, we are using the dummy m
end function
this looks very different from
real function calcMonth(m)
real m ! Hmmm, a local m
calcMonth = 10*m ! Oh noes, which m am I using?
end function
These are potentially different, but the only difference is that in the first m - the dummy argument - is being implicitly typed, in the second m - still the dummy argument - is being explicitly typed. [With the default implicit typing rules m would be integer, so this is the potential difference alluded to before.]
Some languages allow one to specify types and attributes (or equivalent) like
real function calcMonth(integer m)
but Fortran isn't one of those. Crucially, also, the type of the dummy argument doesn't come from the actual argument.
integer month
call calcMonth(month)
end
real function calcMonth(m)
real m
calcMonth = 10*m ! Still the dummy m
end function
is still not declaring a local variable m - with the thought that the dummy m is previously declared an integer, or somehow is the actual argument month, and so the type mismatch means it must be a new variable - and most likely at run-time something unwanted will happen.
I'm experimenting with variable arguments in C++, using va_args. The idea is useful, and is indeed something I've used a lot in C# via the params functionality. One thing that frustrates me is the following excerpt regarding va_args, above:
Notice also that va_arg does not determine either whether the retrieved argument is the last argument passed to the function (or even if it is an element past the end of that list).
I find it hard to believe that there is no way to programmatically determine the number of variable arguments passed to the function from within that function itself. I would like to perform something like the following:
void fcn(int arg1 ...)
{
va_list argList;
va_start(argList, arg1);
int numRemainingParams = //function that returns number of remaining parameters
for (int i=0; i<numRemainingParams; ++i)
{
//do stuff with params
}
va_end(argList);
}
To reiterate, the documentation above suggests that va_arg doesn't determine whether the retrieved arg is the last in the list. But I feel this information must be accessible in some manner.
Is there a standard way of achieving this?
I find it hard to believe that there is no way to programmatically determine the number of variable arguments passed to the function from within that function itself.
Nonetheless, it is true. C/C++ do not put markers on the end of the argument list, so the called function really does not know how many arguments it is receiving. If you need to mark the end of the arguments, you must do so yourself by putting some kind of marker at the end of the list.
The called function also has no idea of the types or sizes of the arguments provided. That's why printf and friends force you to specify the precise datatype of the value to interpolate into the format string, and also why you can crash a program by calling printf with a bad format string.
Note that parameter passing is specified by the ABI for a particular platform, not by the C++/C standards. However, the ABI must allow the C++/C standards to be implementable. For example, an ABI might want to pass parameters in registers for efficiency, but it might not be possible to implement va_args easily in that case. So it's possible that arguments are also shadowed on the stack. In almost no case is the stack marked to show the end of the argument list, though, since the C++/C standards don't require this information to be made available, and it would therefore be unnecessary overhead.
The way variable arguments work in C and C++ is relatively simple: the arguments are just pushed on the stack and it is the callee's responsibility to somewhat figure out what arguments there are. There is nothing in the standard which provides a way to determine the number of arguments. As a result, the number of arguments are determined by some context information, e.g., the number of elements referenced in a format string.
Individual compilers may know how many elements there are but there is no standard interface to obtain this value.
What you could do instead, however, is to use variadic templates: you can determine very detailed information on the arguments being passed to the function. The interface looks different and it may be necessary to channel the arguments into some sort of data structure but on the upside it would also work with types you cannot pass using variable arguments.
No, there isn't. That's why variable arguments are not safe. They're a part of C, which lacks the expressiveness to achieve type safety for "convenient" variadic functions. You have to live with the fact that C contains constructions whose very correctness depends on values and not just on types. That's why it is an "unsafe language".
Don't use variable arguments in C++. It is a much stronger language that allows you to write equally convenient code that is safe.
No, there's no such way. If you have such a need, it's probably best to pack those function parameters in a std::vector or a similar collection which can be iterated.
The variable argument list is a very old concept inherited from the C history of C++. It dates back to the time where C programmers usually had the generated assembler code in mind.
At that time the compiler did not check at all if the data you passed to a function when calling it matched the data types the function expected to receive. It was the programmer's responsibility to do that right. If, for example, the caller called the function with a char and the function expected an int the program crashed, although the compiler didn't complain.
Today's type checking prevents these errors, but with a variable argument list you go back to those old concepts including all risks. So, don't use it if you can avoid it somehow.
The fact that this concept is several decades old is probably the reason that it feels wrong compared to modern concepts of safe code.
I'm trying to fix something in some Objective C++ (?!) code. I don't know either of those languages, or any of the relevant APIs or the codebase, so I'm getting stymied left and right.
Say I have:
Vector<char, sizeof 'a'>& sourceData();
sourceData->append('f');
When i try to compile that, I get:
error: request for member 'append' in 'WebCore::sourceData', which is of non-class type 'WTF::Vector<char, 1ul >& ()();
In this case, Vector is WTF::Vector (from WebKit or KDE or something), not STD::Vector. append() very much is supposed to be a member of class generated from this template, as seen in this documentation. It's a Vector. It takes the type the template is templated on.
Now, because I never write programs in Real Man's programming languages, I'm hella confused about the notations for references and pointers and dereferences and where we need them.
I ultimately want a Vector reference, because I want to pass it to another function with the signature:
void foobar(const Vector<char>& in, Vector<char>& out)
I'm guessing the const in the foobar() sig is something I can ignore, meaning 'dont worry, this won't be mangled if you pass it in here'.
I've also tried using .append rather than -> because isn't one of the things of C++ references that you can treat them more like they aren't pointers? Either way, its the same error.
I can't quite follow the error message: it makes it sound like sourceData is of type WTF:Vector<char, 1ul>&, which is what I want. It also looks from the those docs of WTF::Vector that when you make a Vector of something, you get an .append(). But I'm not familiar with templates, either, so I can't really tell i I'm reading that right.
EDIT:
(This is a long followup to Pavel Minaev)
WOW THANKS PROBLEM SOLVED!
I was actually just writing an edit to this post that I semi-figured out your first point after coming across a reference on the web that that line tells the compiler your forward declaring a func called sourceData() that takes no params and returns a Vector of chars. so a "non-class type" in this case means a type that is not an instance of a class. I interpreted that as meaning that the type was not a 'klass', i.e. the type of thing you would expect you could call like .addMethod(functionPointer).
Thanks though! Doing what you suggest makes this work I think. Somehow, I'd gotten it into my head (idk from where) that because the func sig was vector&, I needed to declare those as &'s. Like a stack vs. heap pass issue.
Anyway, that was my REAL problem, because I tried what you'd suggested about but that doesn't initialize the reference. You need to explicitly call the constructor, but then when I put anything in the constructor's args to disambiguate from being a forward decl, it failed with some other error about 'temporary's.
So in a sense, I still don't understand what is going on here fully, but I thank you heartily for fixing my problem. if anyone wants to supply some additional elucidation for the benefit of me and future google people, that would be great.
This:
Vector<char, sizeof 'a'>& sourceData();
has declared a global function which takes no arguments and returns a reference to Vector. The name sourceData is therefore of function type. When you try to access a member of that, it rightfully complains that it's not a class/struct/union, and operator-> is simply inapplicable.
To create an object instead, you should omit the parentheses (they are only required when you have any arguments to pass to the constructor, and must be omitted if there are none):
Vector<char, sizeof 'a'> sourceData;
Then you can call append:
sourceData.append('f');
Note that dot is used rather than -> because you have an object, not a pointer to object.
You do not need to do anything special to pass sourceData to a function that wants a Vector&. Just pass the variable - it will be passed by reference automatically:
foobar(sourceData, targetData);
Dipping your toes in C++ is never much fun. In this case, you've run into a couple of classic mistakes. First, you want to create an instance of Vector on the stack. In this case the empty () is interpreted instead as a declaratiton of a function called sourceData that takes no agruments and returns a reference to a Vector. The compiler is complaining that the resulting function is not a class (it's not). To create an instance of Vector instead, declare the instance without the () and remove the &. The parentheses are only required if you are passing arguments to the instance constructor and must be omitted if there are no arguments.
You want
Vector<char, sizeof 'a'> sourceData;
sourceData.append('f');
Vector<char, sizeof 'a'> outData; //if outData is not instantiated already
foobar(sourceData, outData);
This Wikipedia article gives a decent introduction to C++ references.