coffee script testing if not defined - coffeescript

according to the coffee script site
console.log(s) if s?
should generate
if (typeof s !== "undefined" && s !== null) {
console.log(s);
}
But what is showing up in my browser is
if (s != null) {
return console.log(s);
}
Using coffee-script-source (1.6.2), coffee-rails (3.2.2), rails-backbone (0.7.2), rails (3.2.13)
Here is my coffee script function. any thoughts on why I am not getting what coffee script site says I should??
window.p = (s) ->
console.log(s) if s?

If you say just a bare:
console.log(s) if s?
then you will indeed get the JavaScript you're expecting (demo):
if (typeof s !== "undefined" && s !== null) {
console.log(s);
}
However, if s is a known variable such as here:
f = (s) -> console.log(s) if s?
then you'll get (demo):
if (s != null) {
//...
}
for the s? test.
So why the difference? In the first case, CoffeeScript cannot guarantee that there is an s variable in existence anywhere so it must do a typeof s check in order to avoid a ReferenceError exception.
However, if s is known to exist because it is a function parameter or has been assigned to as a local variable (so that CoffeeScript will produce a var s), then you don't need the typeof s check since you cannot, in this case, get a ReferenceError.
That leaves us with s !== null versus s != null. Dropping down to non-strict inequality (s != null) allows you to check if s is undefined or null with a single comparison. When you check typeof s !== "undefined", you wrapping the undefined test in with the "is there an s variable" check and a strict s !== null test is all that you need to check for null.

You're right,
(s) -> console.log(s) if s?
console.log(x) if x?
compiles to
(function(s) {
if (s != null) {
return console.log(s);
}
});
if (typeof x !== "undefined" && x !== null) {
console.log(x);
}
It looks like the CoffeeScript compiler is optimizing the Javascript a little bit for you, because in the case of a function argument like this, typeof s will never be undefined as s is defined right there in the function signature, even if its value is null.

Related

NullReferenceException when gamepad is disconnected

I'm using New Input system on my game and I'm having this error
NullReferenceException: Object reference not set to an instance of an object
PauseMenu.Update ()
pointing to this line:
if (gamepad.startButton.wasPressedThisFrame || keyboard.pKey.wasPressedThisFrame)
whenever the gamepad is not connected.
void Update()
{
var gamepad = Gamepad.current;
var keyboard = Keyboard.current;
if (gamepad == null && keyboard == null)
return; // No gamepad connected.
if (gamepad.startButton.wasPressedThisFrame || keyboard.pKey.wasPressedThisFrame)
{
if (GameIsPaused)
{
Resume();
}
else
{
Pause();
}
}
}
How can I fix this?
The issue is that the exit condition requires that both keyboard and gamepad are null. In the case that gamepad is null and keyboard is not (or the other way around), an attempt is made to access a member of the null object.
You can resolve the issue by comparing each object against null before accessing its properties.
if ((gamepad != null && gamepad.startButton.wasPressedThisFrame) ||
(keyboard != null && keyboard.pKey.wasPressedThisFrame)
)
{
// Pause / Resume
}
You could also use the null conditional operator ? in each condition. When the preceding object is null, the resulting value is null. Then using the null coalescing operator ?? we convert this null value to a bool (false in this case because a null button cannot be "pressed").
if (gamepad?.startButton.wasPressedThisFrame ?? false ||
keyboard?.pKey.wasPressedThisFrame ?? false)

Flutter functions Null safety errors

Got the following errors and don't know how to update the code to solve it.
Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
'Function' is from 'dart:core'.
Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
The code:
enum PageName {
welcomePage,
register,
login,
editProfile,
showProfile,
resetPassword,
errorUserExists,
}
Map<PageName, Function> pageName_pageFunction_map = {
PageName.welcomePage: showWelcomePage,
PageName.register: showRegisterPage,
PageName.login: showLoginPage,
PageName.editProfile: showEditProfile,
PageName.showProfile: showUserProfile,
PageName.resetPassword: showResetPassword,
PageName.errorUserExists: showErrorUserExists,
};
void main() {
PageName nextPage = pageName_pageFunction_map[PageName.welcomePage]();
if (nextPage != null) {
while (true) {
PageName nextPage2 = pageName_pageFunction_map[nextPage]();
if (nextPage2 != null) {
nextPage = nextPage2;
}
}
}
}
Can you help me? Thank you
The error message tell that you can't execute a function because this one might be null, and if you execute a function on a null value it will break the program. You have two solution :
First you can make sure that your function isn't null with a test :
if (myFunction != null) {
myFunction()
}
Or you can tell the compiler that your function is not null with the ! operator
myFunction!()
Error: Can't use an expression of type 'Function?' as a function
because it's potentially null.
When you look up one of your functions from the map like pageName_pageFunction_map[PageName.welcomePage] you get a value of type Function?. This is because if you enter a key which does not have a corresponding value, you will get back null from the expression.
The following error message gives you a suggestion on how to solve this problem.
'Function' is from 'dart:core'. Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
You can place ?.call directly before the argument list () to safely call the function;
pageName_pageFunction_map[PageName.welcomePage]?.call();

Type guarding React.KeyboardEvent to reuse event handlers

I created a search-bar-React-Component that resembles the one by Google.
It should fire off a search based on the input if I either click on the 'search' icon or if I hit the enter key.
I want to reuse the same function for both the click and the keydown handler:
...
var [searchParam, setSearchParam] = useState('');
function initSearch(
e:
| React.MouseEvent<HTMLButtonElement>
| React.KeyboardEvent<HTMLInputElement>
): void {
if (e.type == 'click' || (e.type == 'keydown' && e.key == 'Enter')) {
console.log(searchParam); /* ⬆️ this throws the error */
}
}
...
TypeScript keeps giving me the following error:
'Property 'key' does not exist on type 'MouseEvent<HTMLButtonElement, MouseEvent>'
I tried both of the following:
(e instance of KeyboardEvent && e.key == 'Enter') // This is always false, since e is a React.KeyboardEvent
(e instance of React.KeyboardEvent) // KeyboardEvent is not a property of React.
What is a good way to typeguard? Is there a better way to write the function?
Thank you.
Turns out using an intersection type solved the problem:
function initSearch(
e:
| (React.MouseEvent<HTMLButtonElement> & { type: 'click' }) /*⬅️*/
| (React.KeyboardEvent<HTMLInputElement> & { type: 'keydown' }) /*⬅️*/
): void {
if (e.type == 'click' || (e.type == 'keydown' && e.key == 'Enter')) {
console.log(searchParam);
}
}
I checked the type definitions, turns out the 'type' property is only defined as 'string', not as a definite primitive value.
In case I'm missing something here (i.e. that a keydown event can somehow not include the e.type == 'keydown' property), please let me know.
It feels unnecessarily hacky!

Set custom filters for boost log sink with custom attribute & severity level

I have a log setup in which I have 2 types of log messages:
1 based solely on severity level
1 based solely on a custom tag attribute
These attributes are defined as follows:
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
I want to create a filter function that allows a message to be added to my log based on either of the 2 criteria (note that the log messages based on the custom tag attribute are always printed with severity level info, based on the trivial logger's severity levels).
So I want to have a filter, which allows a message based on if a message has the custom tag, and if it does not have it, based on the severity of the message.
I have tried to have a relative simple filter which does the following:
sink_->set_filter(
trivial::severity >= severityLevel
|| (expr::has_attr(tag_attr) && tag_attr == "JSON" && logJson_)
);
But as it is possible that the severityLevel can be either Debug, Info, Warning, Error or Fatal, if the level is configured as either Debug or Info, the custom tag attribute is ignored by the filter.
I have tried using a c++11 lambda, as following:
sink_->set_filter([this, severityLevel](const auto& attr_set) {
if (<condition for custom tag first>) {
return true;
} else if (<condition for severity level second>) {
return true;
} else {
return false;
}
});
But then I don't have an idea on how to actually check for my conditions. I have tried the following:
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
return true;
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
return true;
} else {
return false;
}
But the compiler throws several errors about this:
Core/Source/Log/Logger.cpp: In lambda function:
Core/Source/Log/Logger.cpp:127:48: error: expected primary-expression before '>' token
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
^
Core/Source/Log/Logger.cpp:127:50: error: expected primary-expression before ')' token
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
^
Core/Source/Log/Logger.cpp:129:72: error: expected primary-expression before '>' token
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
^
Core/Source/Log/Logger.cpp:129:74: error: expected primary-expression before ')' token
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
^
Core/Source/Log/Logger.cpp: In lambda function:
Core/Source/Log/Logger.cpp:134:5: error: control reaches end of non-void function [-Werror=return-type]
});
^
cc1plus: all warnings being treated as errors
scons: *** [obj/release/Core/Source/Log/Logger.os] Error 1
====5 errors, 0 warnings====
I have been scouring the boost log documentation about extracting the attributes myself, but I cannot find the information I need.
EDIT:
For posterity, I'll add how I've solved my issue (with thanks to the given answer by Andrey):
sink_->set_filter([this, severityLevel](const auto& attr_set) {
if (attr_set[tag_attr] == "JSON") {
return logJson_;
} else if (attr_set[severity] >= severityLevel) {
return true;
} else {
return false;
}
});
The filter can be written in multiple ways, I will demonstrate a few alternatives.
First, using expression templates you can write it this way:
sink_->set_filter(
(expr::has_attr(tag_attr) && tag_attr == "JSON" && logJson_) ||
trivial::severity >= severityLevel
);
Following the normal short-circuiting rules of C++, the tag attribute will be tested first and if that condition succeeds, the severity will not be tested. If the tag is not present or not JSON or logJson_ is not true, then severity level is tested.
Note that the filter above will save copies of its arguments (including logJson_ and severityLevel) at the point of construction, so if you change logJson_ later on the filter will keep using the old value. This is an important difference from your later attempts with C++14 lambdas, which access logJson_ via the captured this pointer. If you actually want to save a reference to your member logJson_ in the filter, you can use phoenix::ref:
sink_->set_filter(
(expr::has_attr(tag_attr) && tag_attr == "JSON" && boost::phoenix::ref(logJson_)) ||
trivial::severity >= severityLevel
);
However, you should remember that the filter can be called concurrently in multiple threads, so the access to logJson_ is unprotected. You will have to implement your own thread synchronization if you want to update logJson_ in run time.
Barring multithreading issues, your second attempt with a lambda is almost correct. The compiler is complaining because the lambda function is a template, and the result of attr_set["Tag"] expression depends on one of the template parameters (namely, the type of attr_set). In this case, the programmer has to qualify that the following extract<std::string>() expression is a template instantiation and not a sequence of comparisons. This is done by adding a template keyword:
if (attr_set["Tag"].template extract<std::string>() == "JSON" && logJson_) {
return true;
} else if (attr_set["Severity"].template extract<trivial::severity_level>() >= severityLevel) {
return true;
} else {
return false;
}
Note that you could use a standalone function to the same effect, which wouldn't require the template qualification:
if (boost::log::extract<std::string>("Tag", attr_set) == "JSON" && logJson_) {
return true;
} else if (boost::log::extract<trivial::severity_level>("Severity", attr_set) >= severityLevel) {
return true;
} else {
return false;
}
Finally, the preferred way to extract attribute values is to leverage attribute keywords, which you declared previously. Not only this allows to avoid the template qualification quirk but it also removes a lot of code duplication.
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
if (attr_set[tag_attr] == "JSON" && logJson_) {
return true;
} else if (attr_set[severity] >= severityLevel) {
return true;
} else {
return false;
}
The attribute value name and type are inferred from the keyword declaration in this case. This use of attribute keywords is documented at the end of this section.

how to change multiple function arguments into coffescrpt

here is the javascript:
$inputor.on("keyup.inputor", $.proxy(function(e) {
var stop_key = e.keyCode == 40 || e.keyCode == 38
lookup = !(this.view.isShowing() && stop_key)
if (lookup) this.lookup()
},this))
how can i translate it into coffesscript? the first argument of a function like $.proxy is a function and still have a second one.
my solution is assign a variable for the first argument, the function, and poss it to $.proxy.
but i want a better solution.
coffeescript:
??????
Instead of using the jQuery.proxy function, you could use the CoffeeScript fat arrow => since the context you're trying to use is this
$inputor.on "keyup.inputor", (e) =>
stop_key = e.keyCode == 40 || e.keyCode == 38
lookup = !(#view.isShowing() && stop_key)
#lookup() if lookup