I just found in the documentation that FloatToStr and DateToStr are not thread-safe in their one-paramater overloads. The reason is that they access localization information stored in global variables.
My question is: is this of any practical relevance if I do not change the format settings at runtime? As far as I understand it, I'm on the safe side as long as everyone only reads the format settings - even from multiple threads.
Is that true or am I missing something here?
Thanks.
FloatToStr, DateToStr and others similar functions are reading global format settings. So, if your application does not change these settings for these function calls, then it is thread safe. The following code on opposite is not thread safe:
DecimalSeparator := ',';
try
s := FloatToStr(123.45);
finally
DecimalSeparator := '.';
end;
When you need the tread safety and "local" format settings, then you have to use overloaded functions, which take as last parameter: AFormatSettings: TFormatSettings. So, to make above code thread safe you have to write:
var
fs: TFormatSettings;
GetLocaleFormatSettings(GetThreadLocale, fs);
fs.DecimalSeparator := ',';
s := FloatToStr(123.45, fs);
Notes:
GetLocaleFormatSettings and fs initialization may be called once and then fs may be used multiple times. This will speedup the code.
Instead of GetLocaleFormatSettings may be used TFormatSettings.Create. I am not sure when that was introduced, but I see that in Delphi XE.
Even the global settings can change when Application.UpdateFormatSettings (Delphi 7, don't know about Delphi XE) is True. When a user changes the Regional and Language options of Windows, this will be reflected in your application. You can circumvent this by setting UpdateFormatSettings to False, but even then you can't be sure, maybe there is some third party library you use that changes it.
I had some problems with our own application: Nowhere in our application the global formatsettings were changed, but still there was information loss because a float was converted to a string and when the string was converted back to float, the formatsettings were magically changed. (So you had this: 1.2 -> convert to string -> '1.2' -> black magic that changed formatsettings.decimalseparator -> convert to float -> 12).
My suggestion: only use the not thread-safe version for UI purposes so the user sees dates and floats the way he likes them to see, for everything else, use the thread-safe version. Conversions inside your application will then be consistent and don't give surprises.
If the global settings are not changed by another thread while FloatToStr or DateToStr are executed you are fine.
EDIT: one thing to keep in mind:
var
// Note: Using the global FormatSettings variable corresponds to using the
// individual global formatting variables and is not thread-safe.
FormatSettings: TFormatSettings absolute CurrencyString;
The global variable above is just an alias for the global variables listed below. It is possible to change them either through the FormatSettings variable or directly.
var
// Important: Do not change the order of these declarations, they must
// match the declaration order of the fields in TFormatSettings exactly!
CurrencyString: string deprecated 'Use FormatSettings.CurrencyString';
CurrencyFormat: Byte deprecated 'Use FormatSettings.CurrencyFormat';
CurrencyDecimals: Byte deprecated 'Use FormatSettings.CurrencyDecimals';
DateSeparator: Char deprecated 'Use FormatSettings.DateSeparator';
TimeSeparator: Char deprecated 'Use FormatSettings.TimeSeparator';
ListSeparator: Char deprecated 'Use FormatSettings.ListSeparator';
ShortDateFormat: string deprecated 'Use FormatSettings.ShortDateFormat';
LongDateFormat: string deprecated 'Use FormatSettings.LongDateFormat';
TimeAMString: string deprecated 'Use FormatSettings.TimeAMString';
TimePMString: string deprecated 'Use FormatSettings.TimePMString';
ShortTimeFormat: string deprecated 'Use FormatSettings.ShortTimeFormat';
LongTimeFormat: string deprecated 'Use FormatSettings.LongTimeFormat';
ShortMonthNames: array[1..12] of string deprecated 'Use FormatSettings.ShortMonthNames';
LongMonthNames: array[1..12] of string deprecated 'Use FormatSettings.LongMonthNames';
ShortDayNames: array[1..7] of string deprecated 'Use FormatSettings.ShortDayNames';
LongDayNames: array[1..7] of string deprecated 'Use FormatSettings.LongDayNames';
ThousandSeparator: Char deprecated 'Use FormatSettings.ThousandSeparator';
DecimalSeparator: Char deprecated 'Use FormatSettings.DecimalSeparator';
TwoDigitYearCenturyWindow: Word deprecated 'Use FormatSettings.TwoDigitYearCenturyWindow';
NegCurrFormat: Byte deprecated 'Use FormatSettings.NegCurrFormat';
I just had problem with decimal separator. Delphi's streaming system (readcomponent/writecomponent etc) simply changes it to '.' and after all the work is done, it is changed back to whatever it was.
So, when I used this system for my own purposes (serializing/deserializing rather complex structure) and decided to do it in separate thread, or even in several separate threads, it shot me to the leg: '.' were mixed with ',' somewhere.
Unfortunately, I saw in some other libraries when DecimalSeparator is simply changed in procedure with intention to change it back at the end (most careful ones put it in 'finally' clause), so if some of your code is executed when one of these libs are running in separate thread, using thread-safe versions of StrToFloat etc. is imperative.
Related
The documentation for --frozen-intrinsics says:
Only the root context is supported. There is no guarantee that globalThis.Array is indeed the default intrinsic reference. Code may break under this flag
I couldn't understand this. Can someone help me understand this in simple words with an example?
Background: I was checking nicolo-ribaudo/jest-light-runner where there is a mention of --frozen-intrinsics.
When you use --frozen-intrinsics, all the built-in JavaScript objects and functions are recursively frozen, except for globalThis.
If you run node --frozen-intrinsics, you can check it:
> Object.isFrozen(Array)
true
> Object.isFrozen(Array.prototype)
true
> Object.isFrozen(globalThis);
false
> Array.isArray = () => true; Array.isArray(2); // you cannot modify built-in properties, this will not return true
false
> globalThis.foo = 3; foo; // you can still define new globals
3
> globalThis.Array = 4; Array; // However, you can also replace existing globals
4
This prevents your code from accidentally modifying globals, so I recommended it in jest-light-runner to prevent tests from accidentally influencing each other (since it doesn't isolate test files like Jest's default runner does).
Note that you still have a communication channel by attaching new properties to the global object, so it's not an isolation mechanism.
Now, lets take a look at the docs you quoted.
Only the root context is supported.
In Node.js, you can create multiple "global contexts" using the vm built-in module. --frozen-intrinsics does not affect those contexts, so if you run node with --frozen-intrinsics:
> Object.isFrozen(Array)
true
> Object.isFrozen(require("vm").runInNewContext("Array"))
false
There is no guarantee that globalThis.Array is indeed the default intrinsic reference.
As mentioned earlier, globalThis.Array could still be replaced. However, if you have a "safe reference" to an object (either using syntax, or by storing the original Array global in a local variable), you can be sure that it's not modified:
let OriginalArray = Array;
require("untrusted-module");
globalThis.Array; // this might have been replaces
[].push; // this is still the original one
OriginalArray.isArray; // this is still the original one
Code may break under this flag
If code needs to modify built-ins, it would obviously stop working. For example, you cannot use polyfills that modify the global objects.
The question is simple, how do we make es6 modules act like the ImportScript function used on the web browser.
Explanation
The main reason is to soften the blow for developers as they change their code from es5 syntax to es6 so that the transition does not blow up your code the moment you make the change and find out there are a thousand errors due to missing inclusions. It also give's people the option to stay as is indefinitely if you don't want to make the full change at all.
Desired output
ImportScript(A file path/'s); can be applied globally(implicitly) across subsequently required code and vise-verse inside a main file to avoid explicit inclusion in all files.
ES6 Inclusion
This still does not ignore the fact that all your libraries will depend on modules format as well. So it is inevitable that we will still have to include the export statement in every file we need to require. However, this should not limit us to the ability to have a main file that interconnects them all without having to explicitly add includes to every file whenever you need a certain functionality.
DISCLAIMER'S
(Numbered):
(Security) I understand there are many reasons that modules exist and going around them is not advisable for security reasons/load times. However I am not sure about the risk (if any) of even using a method like "eval()" to include such scripts if you are only doing it once at the start of an applications life and to a constant value that does not accept external input. The theory is that if an external entity is able to change the initial state of your program as is launched then your system has already been compromised. So as it is I think the whole argument around Globalization vs modules boils down to the project being done(security/speed needed) and preference/risk.
(Not for everyone) This is a utility I am not implying that everyone uses this
(Already published works) I have searched a lot for this functionality but I am not infallible to err. So If a simple usage of this has already been done that follows this specification(or simpler), I'd love to know how/where I can attain such code. Then I will promptly mark that as the answer or just remove this thread entirely
Example Code
ES5 Way
const fs = require('fs');
let path = require('path');
/* only accepts the scripts with global variables and functions and
does not work with classes unless declared as a var.
*/
function include(f) {
eval.apply(global, [fs.readFileSync(f).toString()])
}
Main file Concept example:
ImportScript("filePath1");loaded first
ImportScript("filePath2");loaded second
ImportScript("filePath3");loaded third
ImportScript("filePath4");loaded fourth
ImportScript("filePath5");loaded fifth
ImportScript("someExternalDependency");sixth
/* where "functionNameFromFile4" is a function defined in
file4 , and "variableFromFile2" is a global dynamic
variable that may change over the lifetime of the
application.
*/
functionNameFromFile4(variableFromFile2);
/* current context has access to previous scripts contexts
and those scripts recognize the current global context as
well in short: All scripts should be able to access
variables and functions from other scripts implicitly
through this , even if they are added after the fact
*/
Typical exported file example (Covers all methods of export via modules):
/*where "varFromFile1" is a dynamic variable created in file1
that may change over the lifetime of the application and "var" is a
variable of type(varFromFile4) being concatenated/added together
with "varFromFile4".
*/
functionNameFromFile4(var){
return var+varFromFile1;
}
//Typical export statement
exportAllHere;
/*
This is just an example and does not cover all usage cases , just
an example of the possible functionality
*/
CONCLUSION
So you still need to export the files as required by the es6 standard , however you only need to import them once in a main file to globalize their functionality across all scripts.
I'm not personally a fan of globalizing all the exports from a module, but here's a little snippet that shows you how one ESM module's exports can be all assigned to the global object:
Suppose you had a simple module called operators.js:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
You can import that module and then assign all of its exported properties to the global object with this:
import * as m from "./operators.js"
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
// can now access the exports globally
add(1, 2);
FYI, I think the syntax:
include("filePath1")
is going to be tough in ESM modules because dynamic imports in an ESM module using import (which is presumably what you would have to use to implement the include() function you show) are asynchronous (they return a promise), not synchronous like require().
I wonder if a bundler or a transpiler would be an option?
There is experimental work in nodejs related to custom loaders here: https://nodejs.org/api/esm.html#hooks.
If you can handle your include() function returning a promise, here's how you put the above code into that function:
async function include(moduleName) {
const m = await import(moduleName);
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
return m;
}
I used this:
Local<Value> argv[argc] = { String::New("hello world") };
But now I see the example on node.js website:
Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
What does it mean? What's difference, when an dwhy I should use Local<Value> in addition to String::New()
Apparently, the node.js example in this case was wrong/inefficient.
https://github.com/joyent/node/commit/98aad77f466d9c36947f2cbb6d07b75009795ed2#commitcomment-5532648
jnardone added a note 2 hours ago
Was this just one of those things that was always wrong, or was there
an underlying v8 change that meant that this should change? The
additional Local::New always looked odd but I can't tell if something
buried inside v8 required this additional wrapper or not.
bnoordhuis added a note 7 minutes ago
It's cleanup. Creating a Local out of a Local is not
actively harmful but it's superfluous and slightly inefficient.
So, your first format is fine.
I've got a record, see this question for background info.
TDigits = AnsiString; //Should be `= array of NativeUInt`, but string has COW
TBigint = record
Digit: TDigits; // Unsigned number, LSB stored in D[0], MSB in D[size-1]
Size: Byte; // Mininum = 4, maximum 127.
MSI: Byte; // Most significant (native)integer minimum=1, maximum=127
Sign: Shortint;
class operator Implicit(a: Integer): TBigint;
Background
I'm using a bignum class that (almost) works like normal integers.
So a:= 1000000*10000000*12000000*10000000*1000000; yields perfectly useful results.
For this purpose I use a record with class operators.
These trigger automatic type conversion and initialisation.
Except when there is no conversion, because I'm assigning a TBigint to another TBigint.
The solution
Use an Ansistring to store the core data, it's got copy-on-write and will clone itself when needed.
The problem: (COW does not work if Delphi does not know you're altering the string)
I've got a few pure assembler routines that manipulate the Digit dynamic array disguised as Ansistring.
However when I do something like this:
Label1.Caption:= BigintToStr(b);
..... this fires:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x; <<-- assignment, locX and X are joined at the hip.
repeat
D := DivBigint(LocX, 1000000000, LocX); <<-- this routine changes LocX
^^+-- but assembler routines bypass COW
X and LocX are joint at the hip, whatever happens to one happens to the other.
Clearly Delphi does not know that the asm routine DivBigint is changing LocX and therefore a COW is in order.
The workaround
If I change the routine to:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x;
LocX.Digit[2]:= #0; <<-- inconsequential change to force COW.
repeat
D := DivBigint(LocX, 1000000000, LocX);
Delphi gets all clued up and performs just fine.
LocX and X are unlinked and everything works fine.
However I don't want to be making silly changes in the middle of some empty space.
Is there a decent/proper/offical* way to force trigger COW in strings?
Something like a system call perhaps?
*circle your favourite option (with a handdrawn circle)
Should be a comment, but need more space...
If you need to call UniqueString or equivalent.
You might as well retain the dynamic record.
A quote from the manual:
Following a call to SetLength, S is guaranteed to reference a unique string or array -- that is, a string or array with a reference count of one. If there is not enough memory available to reallocate the variable, SetLength raises an EOutOfMemory exception.
Note that this behavior even applies when calling SetLength(Length(myArray));.
Delphi will make a copy for you and untangle the problem.
So it turns out there is no need for the complication with the AnsiStrings After all, as long as you call SetLength in every method that accepts the record as a var parameter.
Advantages
This has the added benefit that if you call SetLength to expand the array (as happens often) the added space will be zero-initialized. Something does does not happen with the AnsiString.
Furthermore there is no need to bother with size translations because your array of TXYZ already knows the size of its elements. When using AnsiString you need to add * SizeOf(somestruct) all over the place.
No typecasting is needed, simplifying the code; and in the debugger the data shows up as it is designed.
As you can see the two instances are no longer linked.
Every method that mutates the buffer should, before performing the modification, call UniqueString.
Ensures that a given string has a reference count of one.
In fact, this detail was supplied by Craig Young's comment to my answer to your earlier question.
If you are going to make this viable you are going to need to hide the buffer. Make it strict private. That means that you can only access it from methods of your record. And that way you can be sure that anything that modifies the buffer will call UniqueString.
Personally, I think that a better solution would be to make the type immutable.
How can I define a global function in express.js, that without require I can call it
"How" is simple enough:
global.fnName = function(){ return "hi"; }; // Andreas Hultgren's answer
But you don't need the global prefix; the thing about the global object is ...
fnName = function(){ return "hi"; }; // i.e. don't do: var name = function(){ ... };
console.log(fnName()); // this prints "hi"
console.log(global.fnName()); // this also prints "hi" - it was assigned to global.
"Without require" is a separate consideration: if you don't use require there is no guarantee your "globals" will have been declared by the time you need them. It enforces loading order of dependencies, among other things.
"Why am I" and "Is it correct to" are now hidden questions you should consider. It is accepted in javascript that Global Variables ...
... should be reserved for objects that have system-wide relevance and they should be named to avoid ambiguity and minimize the risk of naming collisions - Angus Croll, Namespacing in Javascript
i.e. global truly is Global: it is used by every author of every plugin or library you pull in to your application, not just you. Naming collisions between global variables break your application. This applies equally in node.js.
Global variables are also thought of as a code smell. In the detail sections below here you will see you can quickly get into trouble by using global variables, and they should really be treated as something that pushes you towards dependency injection and/or namespaces and modules.
Node.js and express - global vars and functions
Here's a good rule: if you upload it to a web server, or share it with other people, don't use global variables.
global is permissible in tiny "Saturday afternoon" apps in node.js with express.js, but tend to cause problems later if they get adopted into production. Therefore:
Modules and exports is best practice.
Injection should also be used to reduce coupling between javascript files. But in all cases you will usually need require to ensure they exist by the time you need them:
You should really consider app.locals data, and/or middleware functions, for anything that is view data related.
// call this as a function with an input object to merge
// the new properties with any existing ones in app.locals
app.locals.({
sayHello: function() { return "hi"; }
});
// now you can also use this in a template, like a jade template
=sayHello()
If you are creating global vars/functions for configuration settings purposes the below comments about namespaces still apply, and there are conventions emerging such as config.json files (still using require) for settings that are globally accessed.
Global variables - simple case
It is simple enough to declare a global variable in javascript, and for a function the process is no different. Simply omit the var keyword which would normally force a local scope on the declaration:
// app.js
blah = "boo";
sayHello = function(string toWho) { return "hello " + toWho; }
getVersion = function() { return "0.0.0.1"; }
// routes/main.js
console.log(blah); // logs: "boo"
console.log(global.blah); // logs: "boo"
console.log(sayHello("World")); // logs: "hello World"
console.log(global.sayHello("World")); // logs: "hello World"
console.log(getVersion()); // logs: "0.0.0.1"
But what if two separate plugins in your project use a global getVersion function - how do you get the right version number? Also, how do you ensure that getVersion exists before you need it, or exists at all?
Why do we need require?
To quote the nodejitsu docs the built in require function ...
... is the easiest way to include modules that exist in separate files. The basic functionality of require is that it reads a javascript file, executes the file, and then proceeds to return the exports object
"So", you may ask, "require just makes sure that a module from another file is included? Why bother?" It's better than that: you can make a whole folder a module, making your code easier to organise and test test test, it will recognise various extensions for file modules, not just .js, and it will look in various folders as well. Of course, it caches as well.
So, now that require has found your module, it ensures the code inside it is executed, and puts the objects your created into a "namespace":
// module file ./myModule.js
exports.blah = "boo";
exports.sayHello = function(string toWho) { return "hello " + toWho; }
// routes/main.js
var demoModuleReference = require('./myModule.js');
console.log(demoModuleReference.blah); // logs: "boo"
console.log(demoModuleReference.sayHello("World")); // logs: "hello World"
In that sample, demoModuleReference is an object that looks like:
{
blah: "foo",
sayHello: [Function]
}
Why modules and not global variables (a.k.a namespacing and "Global is the new private")?
Seems complicated now? Surely global variables are easier? requires ensures the following:
It ensures ordered loading of dependencies
It prevents variable name conflicts within global through the exports object.
This application at mankz.com (chrome or firefox only) is fascinating. Depending on how you use your js code, you are very likely to have variable name conflicts within the global scope. Name conflicts come from everywhere. In a browser, for instance, they can come from extensions. node.js is slightly different, but it is becoming more and more extended by compatible plugins as time goes on (you can load jquery in right now, for example). As the versions go on frameworks will get added, and name collisions in global will become more likely. My last run of that app in chrome showed over 1200 global namespace variables.
Namespaces - why?
This global namespace pollution was publicised early on by Douglas Crockford through Eric Miraglia in the article "A JavaScript Module Pattern". In summary:
All objects that need to be used between js files are really global
So, create a namespace object that will be unique
Assign the return value an anonymous function
Add private methods and variables inside that function
Do something useful with the pattern
Example:
ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () {
var privateField = "can't touch this";
return {
play: function() {
console.log(privateField);
}
}
}
Why is this good?
Now you have only increased the global namespace members in the world by one, but this member contains as many items as you like.
Your application is far less likely to clash with other namespaces
It's a pattern, other frameworks expect you to use it to interact with them properly. In that reference, jQuery is a browser plugin, but you can use it with node and therefore your app, so the library interactivity policy statement is a perfect example.
It's a pattern, if we all follow it we our programs are all more likely to get along
When you read the Crockford reference along with the Croll reference (Direct Assignment section) I mentioned at the start, you see why it looks this complicated rather than just doing: sound.play = function() { ... } - ease of maintenance, refactoring the namespace etc. being just one reason.
Summary
In summary:
Can I create globals? Yes, it's simple, omit the var keyword before the declaration.
Should I create globals? You should use the module pattern, which is implicitly supported by node, and by express
Why am I creating globals? If it's for configuration, use a config namespace (e.g. How to store Node.js deployment settings/configuration files?)
You can:
global.name = function(){};
But you really should avoid using globals, even if it's possible to use them.