I am trying to init a const variable differently based on another const string.
Code is not inside a class, just plain dart.
Only way I found is using the elvis operator but it's quite ugly and will become unmaintanable with many conditions to handle ...
How would you do it ?
test.dart called with --dart-define CONTEXT=context-A:
// can be : "context-A" or "context-B" or "context-C" etc ...
const contextString = String.fromEnvironment('CONTEXT');
const Context contextObject = (contextString == 'context-A')
? ContextA()
: (contextString == 'context-B')
? ContextB()
: ContextC();
Any other method (like calling an init method) fails with dart telling me that I cannot init a const variable with a non const method :(
Thanks
Personally I would use the ternary conditional operator as you're already using; I don't think it's unreadable, and as long as you don't have too many cases (which itself would be a maintenance problem), the indentation creep shouldn't be too bad.
However, one alternative would be to abuse collection-if:
const contextObject = [
if (contextString == 'context-A')
ContextA()
else if (contextString == 'context-B')
ContextB()
else
ContextC()
];
which is formatted more nicely (as long as the expression is sufficiently long that dart format doesn't try to squeeze it all onto a single line). However, I don't recommend this because:
You'll need to some extra overhead of using operator [] everywhere to access the intended object.
Equality comparisons are potential pitfall. contextObject == const [ContextA()] will work, but if const is accidentally omitted, it will never compare equal.
(At some point, perhaps if-expressions will be added to Dart.)
Related
I am wondering about a particular statement in the Moloch v2.1 smart contract code:
https://github.com/Moloch-Mystics/Molochv2.1/blob/main/Flat_Moloch_v2.1.sol
In the Moloch contract, there is a contract level mapping called members
mapping(address => Member) public members;
As expected in almost every line of code that reads or writes to this mapping, square brackets are used. However there is one line of code involving a tuple that uses parentheses instead, wrapping a pair of them around msg.sender:
(,,,bool exists,,) = moloch.members(msg.sender);
Why isn't this line of code using square brackets after the moloch.members reference, like this?:
(,,,bool exists,,) = moloch.members[msg.sender];
I don't understand why that line is using parentheses and what kind of different behavior might result from this. Can someone explain this to me?
For reference purposes, this occurs inside the function below, which is a member of the MolochSummoner contract, which inherits from CloneFactory:
function registerDao(
address _daoAdress,
string memory _daoTitle,
string memory _http,
uint _version
) public returns (bool) {
moloch = Moloch(_daoAdress);
(,,,bool exists,,) = moloch.members(msg.sender);
require(exists == true, "must be a member");
require(daos[_daoAdress] == false, "dao metadata already registered");
daos[_daoAdress] = true;
daoIdx = daoIdx + 1;
emit Register(daoIdx, _daoAdress, _daoTitle, _http, _version);
return true;
}
You can only use brackets if you are accessing the variable inside the same contract.
Outside the contract, when accessing a public variable you are calling a getter function members(). Solidity automatically generates this function for you. There is no get prefix.
More about Solidity getter functions here.
This is a bit confusing and somewhat bad design decision, so I apologize.
Consider the following line of code that doesn't compile in Dart -- lack of comma operator, but comparable things are totally fine in JavaScript or C++:
final foo = (ArgumentError.checkNotNull(value), value) * 2;
The closest I could get with an ugly workaround is
final foo = last(ArgumentError.checkNotNull(value), value) * 2;
with function
T last<T>(void op, T ret) => ret;
Is there a better solution?
Dart does not have a comma operator similar to the one in JavaScript.
There is no obviously better solution than what you already have.
The work-around operation you introduced is how I would solve it. I usually call it seq for "sequence" if I write it.
There is sadly no good way to use an extension operator because you need to be generic on the second operand and operators cannot be generic. You could use an extension method like:
extension Seq on void {
T seq<T>(T next) => next;
}
Then you can write ArgumentError.checkNotNull(value).seq(value).
(For what it's worth, the ArgumentError.checkNotNull function has been changed to return its value, but that change was made after releasing Dart 2.7, so it will only be available in the next release after that).
If the overhead doesn't matter, you can use closures without arguments for a similar effect (and also more complex operations than just a sequence of expressions).
final foo = () {
ArgumentError.checkNotNull(value);
return value;
} ();
This is not great for hot paths due to the overhead incurred by creating and calling a closure, but can work reasonably well outside those.
If you need this kind of test-plus-initialization pattern more than once, the cleanest way would arguably be to put it in a function of its own, anyway.
T ensureNotNull<T>(T value) {
ArgumentError.checkNotNull(value);
return value;
}
final foo = ensureNotNull(value);
As per this excellent explanation const expressions in Dart are "deeply immutable" meaning that nothing inside can ever change and therefore the entire expression will always denote the same thing. This is useful for the compiler, because it can generate the entire object graph once and re-use it every time such an expression occurs, and it is useful for the programmer to know that such an expression –even when it is deeply nested– still follows value-semantics and won't do anything behind my back.
I am using those optimizations by the compiler to use a well-structured object model (instead of hand-encoding it in a bit-vector, for example) and still get good performance. Since we can get some of those benefits also by "explicitly hashing" some values by making them run-time constants with the static final idiom, the question arises which of the two is good style to use in which case?
Consider the following example:
enum ShaftType { RING, SUN, CARRIER }
class Shaft {
final int index;
final ShaftType type;
Shaft(this.type, this.index) {
assert((type == ShaftType.CARRIER) == (index == null));
}
const Shaft.CARRIER()
: type = ShaftType.CARRIER,
index = null;
const Shaft.RING(this.index) : type = ShaftType.RING;
const Shaft.SUN(this.index) : type = ShaftType.SUN;
}
class GearPath {
final Shaft input, output, fixed;
GearPath({this.input, this.output, this.fixed}) {
// input and output must be set
assert(null != input && null != output);
// fixed shaft can't be anything else
assert(fixed != input && fixed != output);
}
GearPath.carrierToFirstRingFixedSun(int i)
: input = const Shaft.CARRIER(),
output = const Shaft.RING(0),
fixed = new Shaft.SUN(i) {}
static final singleFixedSunUp = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.RING(0),
fixed: const Shaft.SUN(0),
);
static final directDrive = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.CARRIER(),
fixed: null,
);
// ...
}
I can't make the main Shaft(..) and GearStage(..) constructors const because I want to check some constraints, but I can provide special-case constructors (such as Shaft.SUN(int i), Shaft.CARRIER()) which comply with those constraints (at least partially) by design and provide users legible shorthands for those common values.
On the other hand, when a const constructor would have no arguments, then I can as well write it as a static final member as I have done with GearStage.directDrive. If all users refer to this static member instead of re-creating the value again, we also get the benefit of sharing memory and fast comparisons (reference to same object). I can't declare the right-side of this definition as const, because it uses the non-const constructor, but developers can see from context that this is indeed a constant value and not global mutable singleton hidden in the static field. So for practical purposes it should be just as good as a const constructor, right?
Since I haven't found this described any where as a best practice my question is simply if this is indeed a good way to combine and trade-off between const constructors and static final "named value instances"?
Finally, I wonder if there is a way to declare GearPath.carrierToFirstRingFixedSun(int i) also as a const constructor? Currently I can't because const Shaft.SUN(i) complains about i not being constant.
(full code of example)
Dart 2 will allow you to have asserts in const constructors (as long as your condition can be computed as a const expression).
Then you will be able to write:
GearPath({this.input, this.output, this.fixed})
: // input and output must be set
assert(null != input && null != output),
// fixed shaft can't be anything else
assert(!identical(fixed, input) && !identical(fixed, output));
Until then, you can't have both validation and const expressions.
You still will not be able to make GearPath.carrierToFirstRingFixedSun(int i) const because it i is not constant. The const Shaft.SUN(i) is still not a valid const expression, even if i is the parameter of a const constructor. Each const Constructor(...) invocation must still create exactly one object, even if it occurs in the initializer list of another const constructor.
As a rule-of-thumb, you should consider whether exposing a value as const instead of final is something you want to commit to. When you make the variable const, it means that someone else can use the value in another const expression, and then changing the variable to final will be a breaking change. Saying that something is const is a commitment that you should choose deliberately, not just because you can. So, consider the use-cases of your variable. If you don't see it being used in other const expressions, then just make it final.
Here is the function
calc.lua:
function foo(n)
return n*2
end
Here is my LuaJavaCall
L.getGlobal("foo");
L.pushJavaObject(8);
int retCode=L.pcall(1,1,0); // nResults)//L.pcall(1, 1,-2);
String errstr = L.toString(-1); // Attempt to perform arithmetic on local variable 'n'
Update: as indicated below I needed to use L.pushNumber(8.0) instead of L.pushJavaObject()
Try using L.pushNumber instead of L.pushJavaObject like this:
L.getGlobal("foo");
L.pushNumber(8.0);
int retCode = L.pcall(1,1,0);
String errstr = L.toString(-1);
Lua probably sees JavaObject as a type of 'userdata' in which case there are no predefined operations for it; Lua won't know what to do with a JavaObject * 2 since you didn't define how to handle it.
OTOH, Lua does know how to handle a number since that's a builtin primitive type. For the code snippet you presented, pushing a number would be the least painful way to get it working instead of writing extra code that tells Lua how to work with numbers wrapped inside a JavaObject.
I want users of my C++ application to be able to provide anonymous functions to perform small chunks of work.
Small fragments like this would be ideal.
function(arg) return arg*5 end
Now I'd like to be able to write something as simple as this for my C code,
// Push the function onto the lua stack
lua_xxx(L, "function(arg) return arg*5 end" )
// Store it away for later
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
However I dont think lua_loadstring will do "the right thing".
Am I left with what feels to me like a horrible hack?
void push_lua_function_from_string( lua_State * L, std::string code )
{
// Wrap our string so that we can get something useful for luaL_loadstring
std::string wrapped_code = "return "+code;
luaL_loadstring(L, wrapped_code.c_str());
lua_pcall( L, 0, 1, 0 );
}
push_lua_function_from_string(L, "function(arg) return arg*5 end" );
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
Is there a better solution?
If you need access to parameters, the way you have written is correct. lua_loadstring returns a function that represents the chunk/code you are compiling. If you want to actually get a function back from the code, you have to return it. I also do this (in Lua) for little "expression evaluators", and I don't consider it a "horrible hack" :)
If you only need some callbacks, without any parameters, you can directly write the code and use the function returned by lua_tostring. You can even pass parameters to this chunk, it will be accessible as the ... expression. Then you can get the parameters as:
local arg1, arg2 = ...
-- rest of code
You decide what is better for you - "ugly code" inside your library codebase, or "ugly code" in your Lua functions.
Have a look at my ae. It caches functions from expressions so you can simply say ae_eval("a*x^2+b*x+c") and it'll only compile it once.