The use of the triple exclamation mark
There is no difference between !a
and !!!a
, since !!!a
is just !!(!a)
and because !a
is a boolean, !!(!a)
is just its double negation, therefore the same.
Triple exclamation marks on R
!!!
is usually used to evaluate a list of expressions.
library(dplyr)
library(rlang)
VC_preds <- c('mpg', 'cyl')
mtcars %>% select(!!!VC_preds) %>% head
# mpg Cyl
#Mazda RX4 21.0 6
#Mazda RX4 Wag 21.0 6
#Datsun 710 22.8 4
#Hornet 4 Drive 21.4 6
#Hornet Sportabout 18.7 8
#Valiant 18.1 6
If VC_preds
is a vector as in your example, !!
should work as well.
mtcars %>% select(!!VC_preds) %>% head
Help page of ?"!!!"
gives a better example to understand the difference.
vars <- syms(c("height", "mass"))
vars
#[[1]]
#height
#[[2]]
#mass
starwars %>% select(!!!vars)
# A tibble: 87 x 2
# height mass
# <int> <dbl>
# 1 172 77
# 2 167 75
# 3 96 32
# 4 202 136
# 5 150 49
# 6 178 120
# 7 165 75
# 8 97 32
# 9 183 84
#10 182 77
# … with 77 more rows
What does the '!!!' syntax mean in javascript?
I assumed it was somewhat equivalent to === and !==...
No, it's just three "not" operators, a "not-not-not".
It's the same as !(!(!(x)))
, and is always equivalent to a single !x
.
There is literally no use for this. !!
is a somewhat cryptic means of converting any variable to its boolean representation, but !!!
is just silly. You can chain an arbitrary number of !
's together, but it isn't useful for anything.
Is !!!foo the same as !foo?
Yup. Just for clarity:
!!x === x
is not generally true, but it is true if x
is already a boolean: "not (not true)" is true, and "not (not false)" is false.
!foo
is always a boolean; if foo
is truthy, it's false
, otherwise it's true
.
So if you substitute !foo
in for x
you get that !!(!foo) === (!foo)
is always true. Removing the parentheses doesn't change the meaning, so !!!foo === !foo
is always true.
Which means there's no good reason to write !!!foo
in actual code. Just use !foo
instead.
What is double exclamation mark in C#?
This is a null-parameter check syntax which was going to be introduced in C# 11. This propsal has since been rolled back following community feedback.
The proposal is here, and the PR doing a first roll-out to the runtime is here.
The syntax:
public void Foo(string bar!!)
{
}
Is roughly equivalent to:
public void Foo(string bar)
{
if (bar is null)
{
throw new ArgumentNullException(nameof(bar));
}
}
... although the actual implementation uses a throw helper, something like:
public void Foo(string bar)
{
<PrivateImplementationDetails>.ThrowIfNull(bar, "bar");
}
[CompilerGenerated]
internal sealed class <PrivateImplementationDetails>
{
internal static void Throw(string paramName)
{
throw new ArgumentNullException(paramName);
}
internal static void ThrowIfNull(object argument, string paramName)
{
if (argument == null)
{
Throw(paramName);
}
}
}
See on SharpLab.
Methods containing throw
statements are less likely to be inlined by the JIT, so using a throw helper makes it more likely that your method can be inlined, which might remove the null-check altogether! See on SharpLab.
Note that the use of !!
is an implementation detail of your method: it just causes the compiler to insert code which you could have written yourself anyway. This means that moving from throw
to !!
(or vice versa) is not a breaking change.
There are a couple of places where !!
will get the compiler to generate code which you can't (easily) write by hand, however.
One place where !!
is particularly useful is in records with primary constructors. For example:
public record Person(string Name!!, int Age);
In order to correctly null-check the Name
parameter in previous versions of C#, you have to write this out longhand:
public record Person
{
public string Name { get; init; }
public int Age { get; init; }
public Person(string name, int age)
{
if (name is null)
throw new ArgumentNullException(nameof(name));
(Name, Age) = (name, age);
}
public void Deconstruct(out string name, out int age) =>
(name, age) = (Name, Age);
}
Another place where !!
does something which you can't write yourself is in chained constructor calls:
public class C
{
public C(int i) { }
public C(string s!!) : this(s.Length) { }
}
This null-checks s
before accessing s.Length
, something like this (which isn't valid C#):
public C(string s)
{
if (s is null)
throw new ArgumentNullException(nameof(s));
C(s.Length);
}
See on SharpLab.
Another interesting aspect is that the null-checks are inserted before field assignments in constructors. For example:
public class C
{
private readonly ExpensiveObject e = new ExpensiveObject();
public C(string s!!) { }
}
Is compiled as:
public class C
{
private readonly ExpensiveObject e;
public C(string s)
{
if (s is null)
throw new ArgumentNullException(nameof(s));
e = new ExpensiveObject();
}
}
That is, the null-check happens before the instantiation of ExpensiveObject
. See on SharpLab.
Is there a more robust rename alternative than select with triple exclamation mark?
An extension to your solution could be
library(tidyverse)
df[,setdiff(mapping, colnames(df))] <- NA
df %>% rename_all(~names(mapping))
# x y z
#1 1 m NA
#2 2 m NA
#3 3 m NA
Or another approach
map_dfc(setdiff(mapping, colnames(df)), ~df %>% mutate(!!.x := NA)) %>%
arrange(mapping) %>%
rename_all(~names(mapping))
What does exclamation mark mean before invoking a method in C# 8.0?
This would be the null forgiving operator.
It tells the compiler "this isn't null, trust me", so it does not issue a warning for a possible null reference.
In this particular case it tells the compiler that Entity
isn't null.
Can somebody explain an exclamation mark?
!
inverts the truthyness of an expression. Since chars
starts out as an empty object, the first time a character is iterated over, it won't exist on a property of the object; it'll be undefined
. Eg, for H
:
chars[character]
// equivalent to
chars.H
// resolves to
undefined
// putting ! in front of it makes it truthy instead:
!undefined -> true
So if(!chars[character]){
is saying: if this character doesn't exist on the object yet, then execute the following block:
chars[character] = 1;
} else {
// The character has already been iterated over;
// it exists on the object, and the value is a number
// Increment that number:
chars[character]++;
}
Related Topics
How to Tell If a String Contains a Certain Character in JavaScript
Creating a Json Dynamically With Each Input Value Using Jquery
How to Reference a JavaScript Object Property With a Hyphen in It
Angular: Toggle Text of Button Based on Boolean Value in Model
How to Execute a Function After Another One
Websocket Connection Failed: Error During Websocket Handshake: Unexpected Response Code: 400
How to Enable Scrolling on Website That Disabled Scrolling
How to Store Data After Refreshing the Web Page
Html Input Type Number Thousand Separator
How to Add or Update a Query String Parameter
How to Make a Bot Delete Messages After a Certain Time Period
Break the Loop of an Array Looping Function (Map, Foreach, etc.)
Print Function Not Working in Chrome
Check If Image Exists on Server Using JavaScript
How to Show Roles of User Discord.Js/Userinfo Command
Regex to Get String Between Curly Braces
How to Get a Div Element from an External Webpage in HTML File