Binding a variable to one of two values with IF? - if-statement

In the following SPARQL query, I'm not sure how to use if to bind one of two strings to the variable ?result. I heard that there are concepts of “in scope” and “out of scope,” but I don't really see the difference. I've also tried putting the if clause in the select line, but it didn't work either. How can I fix this query to bind ?result to one of the two strings based on the condition?
SELECT ?result
WHERE{
?chain rdf:type rdfs:Property .
?chain rdfs:domain <http://www.vs.cs.hs-rm.de/ontostor/SVC#MDiskGroup> .
?chain rdfs:range <http://www.vs.cs.hs-rm.de/ontostor/SVC#IOgroup> .
?this ?chain ?arg .
?arg io:id ?var .
IF(?var = "0"^^xsd:integer,
BIND(" *"^^xsd:string AS ?result),
BIND(""^^xsd:string AS ?result)) .
}

The if operator in SPARQL isn't a statement as it sometimes is in a programming language, but rather is an "function form" for creating an expression (with special evaluation semantics). The value of if(test,a,b) is a if test is true, and b if test is false. As the documentation says:
17.4.1.2 IF
rdfTerm IF (expression1, expression2, expression3)
The IF function form evaluates the first argument, interprets it as a
effective boolean value, then returns the value of expression2 if the
EBV is true, otherwise it returns the value of expression3. Only one
of expression2 and expression3 is evaluated. If evaluating the first
argument raises an error, then an error is raised for the evaluation
of the IF expression.
Examples: Suppose ?x = 2, ?z = 0 and ?y is not bound in some query
solution:
IF(?x = 2, "yes", "no") returns "yes"
IF(bound(?y), "yes", "no") returns "no"
IF(?x=2, "yes", 1/?z) returns "yes", the expression 1/?z is not evaluated
IF(?x=1, "yes", 1/?z) raises an error
IF("2" > 1, "yes", "no") raises an error
So, if isn't a statement like it might be in a programming language, but it's simply a function (though lazily evaluated) that takes three arguments and returns a value. SPARQL is a query language, and doesn't have statements that get executed; it's a query language for matching patterns in a graph and binding variables to values. So if is a function, and it just so happens that if the first argument is true, then it returns the second argument, otherwise it returns the third. In general, you'd bind the value of a function to a variable with
bind( function(args...) as ?variable )
and this case is no different. You'd call the if function and bind its result to a variable with
bind( if(condition,then,else) as ?result )
In your case, this means that you would use the following query. I've added some newlines to help the readability, but they're not necessary. Integers in a SPARQL query are shorthand for a literal with type xsd:integer, so I've also used (thanks to RobV's comment) 0 instead of "0"^^xsd:integer. (See 2.3.2 Matching Literals with Numeric Types.)
bind(if(?var = 0,
" *"^^xsd:string,
""^^xsd:string )
as ?result)
If we actually want to shorten this even more, then we can use xsd:string as a constructor, and do (see 17.5 XPath Constructor Functions):
bind(xsd:string(if(?var = 0," *", "")) as ?result)
This might seem a little bit odd at first if you're used to doing things like
String result;
if ( var == 0 ) {
result = "case 1";
}
else {
result = "case 2";
}
but many language actually provide a ternary operator that lets you do the much shorter
String result = (var == 0) ? "case 1" : "case 2";
instead. This is the functionality you're getting with SPARQL.

Related

Multiple string replaces in one line

I have a sql statement and for debugging I want to print it. The statement contains placeholders and I want to fill the placeholders in one instruction line before I print. Is this valid or UB?
std::string query("SELECT A, B FROM C WHERE D = ? and E = ?;");
std::cout << query.replace(query.find("?"), 1, "123").replace(query.find("?"), 1, "234") << std::endl;
Is the order of the instructions
Find position of first question mark
Replace first string in query
Find position of second question mark after first replacement
Replace second string in query
guaranteed or is it possible that both find operations can be called before both replace operations like
Find position of first question mark
Find position of second question mark before first replacement
Replace first string in query
Replace second string in query
I'm asking because:
Order of evaluation of the operands of almost all C++ operators
(including the order of evaluation of function arguments in a
function-call expression and the order of evaluation of the
subexpressions within any expression) is unspecified. The compiler can
evaluate operands in any order, and may choose another order when the
same expression is evaluated again.
EDIT:
It's not possible to use third party dependencies in this project.
In query.replace(query.find("?"), 1, "123").replace(query.find("?"), 1, "234")
query.find("?") is un-sequenced from each other.
so result is unpredictable between possible sequences.
I cannot find anything in the rules of order of evaluation that strictly specifies the ordering of the function arguments of chained functions. That is to say that in your case you can know that:
The first replace is sequenced before the second one, because the second one operates on its return value
Each find call is sequenced before the replace that uses its return value as an argument
But what you want is for the first replace to be sequenced before the second find and there is no such guarantee. For reference, see the rules here.
You can use boost::algorithm::replace_first multiple times:
#include <boost/algorithm/string/replace.hpp>
#include <iostream>
#include <string>
int main() {
std::string query("SELECT A, B FROM C WHERE D = ? and E = ?;");
for(auto replacement : {"123", "1"})
boost::algorithm::replace_first(query, "?", replacement);
std::cout << query << '\n';
}
Note that this simple string replacement won't work for replacement strings that need quoting.

Shorthand If/Else statement with two statements inside IF

Sorry, I couldn't find a better fitting title, feel free to edit the title if you find a more suthing one. Here is my question, I know I can create a small version of IF/ELSE statement like this:
(condiction) ? numFound = true : numFound = false;
but, is there a way of having two statements inside the first condition, ex.
(condition) ? numFound = true, break: numFound = false;
normal version of if/else statement I want to write
if (condition)
{
numFound = true;
break;
}
else
numFound = false;
Sorry for the noob question, and thanks for the help!
In short, it isn't possible. The Ternary operator requires the operands to evaluate to a value, and code blocks don't. Comma expressions don't work, because they will set the value to the last one executed- break doesn't evaluate to a value. Additionally, break isn't a function to be evaluated, it's a statement.
The advice is to not use conditionals/ternary operators when you are doing things more complex than their base use- they're harder to parse by humans and any decent compiler will compile x = condition ? this:that the same as if(condition){x=this}else{x=that} (or optimize both to the same assembly).
No you cannot do that. The "small version" of the if/else is called the conditional operator. It is the only operator in c++ taking three operands and commonly also simply called "the ternary operator". From here:
Exp1 ? Exp2 : Exp3;
where Exp1, Exp2, and Exp3 are expressions. Notice the use and
placement of the colon. The value of a ? expression is determined like
this: Exp1 is evaluated. If it is true, then Exp2 is evaluated and
becomes the value of the entire ? expression. If Exp1 is false, then
Exp3 is evaluated and its value becomes the value of the expression.
And for some clarification what is an expression see this question. break is not an expression, but a statement, hence you cannot use it inside a ternary.
Anyhow I would advise you not to hide the break within more stuff in a single line. In a loop a break is something extremely important and it makes sense to make it stand out from the "normal" buissness that happens inside the loop. If I dont immediately see a break (or a return) in a loop then I assume that it does its full iteration. Overlooking a break can cause mayor confusion and misunderstanding.
You could use comma expressions. A comma expression of the form (expr1, expr2) evaluates expr1 (and ignores the value to which it evaluates) and then expr2, which's value is then the result of the overall comma expression.
int main(int argc, char* argv[]) {
bool r = (argc==1) ? (printf("no parameters"),true) : (printf("parameters"),false);
return 0;
}
My friend you're in luck. Use comma operator:
(condition) ? numFound=true, x=1, y=2: numFound = false;
Of course if you're specific to break; it won't work.
Your break doesn't work here but the task itself works. But be careful! Strange things can happen. See these examples:
0?printf("One"),printf("One"):printf("Two"),printf("Two"); /* TwoTwo */
0?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* TwoTwo */
1?printf("One"),printf("One"):printf("Two"),printf("Two"); /* OneOneTwo (!) */
1?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* OneOne */
This happens because of the comma operator which evaluates an expression fomr left to right and returns the value of the second statement for the whole expression.
The next step is to check the binding precedence of (), ?: and ,. We find here that the opertators are ordered from strong to weak like
()
?:
,
Therefore the third example I posted is evaluated as follows:
1?printf("One"),printf("One"):printf("Two"),printf("Two")
-> (1?printf("One"),printf("One"):printf("Two")),printf("Two")
-> (printf("One"),printf("One")),printf("Two")
-> OneOneTwo
I do really not recommend using the so called ternary operator in more complicated cases. Stick to clear code. You know "Code is read more than it is written."

Disambiguating std::isalpha() in C++

So I am currently writing a part of a program that takes user text input. I want to ignore all input characters that are not alphabetic, and so I figured std::isalpha() would be a good way to do this. Unfortunately, as far as I know there are two std::isalpha() functions, and the general one needs to be disambiguated from the locale-specific one thusly:
(int(*)(int))std::isalpha()
If I don't disambiguate, std::isalpha seems to return true when reading uppercase but false when reading lowercase letters (if I directly print the returned value, though, it returns 0 for non-alpha chars, 1 for uppercase chars, and 2 for lowercase chars). So I need to do this.
I've done so in another program before, but for some reason, in this project, I sometimes get "ISO C++ forbids" errors. Note, only sometimes. Here is the problematic area of code (this appears together without anything in between):
std::cout << "Is alpha? " << (int(*)(int))std::isalpha((char)Event.text.unicode) << "\n";
if ( (int(*)(int))std::isalpha((char)Event.text.unicode) == true)
{
std::cout << "Is alpha!\n";
//...snip...
}
The first instance, where I send the returned value to std::cout, works fine - I get no errors for this, I get the expected values (0 for non-alpha, 1 for alpha), and if that's the only place I try to disambiguate, the program compiles and runs fine.
The second instance, however, throws up this:
error: ISO C++ forbids comparison between pointer and integer
and only compiles if I remove the (int(*)(int)) snippet, at which point bad behavior ensues. Could someone enlighten me here?
You are casting the return value of the std::alpha() call to int(*)(int), and then compare that pointer to true. Comparing pointers to boolean values doesn't make much sense and you get an error.
Now, without the cast, you compare the int returned by std::alpha() to true. bool is an integer type, and to compare the two different integer types the values are first converted to the same type. In this case they are both converted to int. true becomes 1, and if std::isalpha() returned 2 the comparison ends up with 2 != 1.
If you want to compare the result of std::alpha() against a bool, you should cast that returned in to bool, or simply leave out the comparison and use something like if (std::isalpha(c)) {...}
There is no need to disambiguate, because the there is no ambiguity in a normal call.
Also, there is no need to use the std:: prefix when you get the function declaration from <ctype.h>, which after C++11 is the header you should preferably use (i.e., not <cctype>) – and for that matter also before C++11, but C++11 clinched it.
Third, you should not compare the result to true.
However, you need to cast a char argument to unsigned char, lest you get Undefined Behavior for anything but 7-bit ASCII.
E.g. do like this:
bool isAlpha( char const c )
{
typedef unsigned char UChar;
return !!isalpha( UChar( c ) );
}

Two strings between brackets separated by a comma in C++ [duplicate]

This question already has answers here:
How does the Comma Operator work
(9 answers)
Closed 9 months ago.
I came across unexpected (to me at least) C++ behavior today, shown by the following snippit:
#include <iostream>
int main()
{
std::cout << ("1", "2") << std::endl;
return 0;
}
Output:
2
This works with any number of strings between the parentheses. Tested on the visual studio 2010 compiler as well as on codepad.
I'm wondering why this compiles in the first place, what is the use of this 'feature'?
Ahh, this is the comma operator. When you use a comma and two (or more) expressions, what happens is that all expressions are executed, and the result as a whole is the result of the last expression. That is why you get "2" as a result of this. See here for a bigger explanation.
It's called the comma operator: in an expression x, y, the compiler
first evaluates x (including all side effects), then y; the results
of the expression are the results of y.
In the expression you cite, it has absolutely no use; the first string
is simply ignored. If the first expression has side effects, however,
it could be useful. (Mostly for obfuscation, in my opinion, and it's
best avoided.)
Note too that this only works when the comma is an operator. If it can
be anything else (e.g. punctuation separating the arguments of a
function), it is. So:
f( 1, 2 ); // Call f with two arguments, 1 and 2
f( (1, 2) ); // Call f with one argument, 2
(See. I told you it was good for obfuscation.)
Comma operator ( , )
The comma operator (,) is used to separate two or more expressions that are included where only one expression is expected. When the set of expressions has to be evaluated for a value, only the rightmost expression is considered.
For example, the following code:
a = (b=3, b+2);
Ref:http://www.cplusplus.com/doc/tutorial/operators/
The result of the comma (",") is the right subexpression.
I use it in loops over stl containers:
for( list<int>::iterator = mylist.begin(), it_end = mylist.end(); it != it_end; ++it )
...
The comma operator evaluates the expressions on both sides of the comma, but returns the result of the second.

Does ColdFusion support type hinting?

In PHP I can do:
$var = (int) $_POST['var'];
Is there a way to explicitly set a ColdFusion variable to an integer or a string?
Variables are typeless in CF. Although if you want to evaluate a variable as either a number or string, you could do:
#Val(<variable>)#
and for strings
#ToString(<variable>)#
Depending on what you want to happen for data that can't be converted, maybe you want cfparam?
<cfparam name="form.v" type="numeric"/>
That will throw an exception if form.v is not present or is not numeric.
You can also test whether a value is numeric (or any other type):
<cfif isNumeric(form.v)>
and you can 'convert' a string a numeric value:
<cfset v = val(form.v) />
In addition to the good information in the other answers, it's worth mentioning that you can use isvalid() to see if a typeless value matches a bunch of different criteria:
isvalid('integer',x);
isvalid('float',x);
isvalid('string',x);
...etc. There are also some higher-level ones, like:
isvalid('email',x);
isvalid('telephone',x);
There are times when you must coerce a typeless value into a "true" type -- for instance, when you want to pass an argument to a Java method with more than one signature. You'd use javacast(), like so:
x = "01";
myJavaFunc.doSomething( x ); // ambiguous -- could be a string or number
myJavaFunc.doSomething( javacast('int', x ) ); // does something
myJavaFunc.doSomething( javacast('string', x ) ); // does something else