How to replace multiple "if-else-if" with a map - dictionary

I am getting one concern on multi layer if-else-if condition so I want to make short by using a map.
Please see below code in if-else-if which I want to replace with a map.
function, args := APIstub.GetFunctionAndParameters()
if function == "queryProduce" {
return s.queryProduce(APIstub, args)
} else if function == "initLedger" {
return s.initLedger(APIstub)
} else if function == "createProduce" {
return s.createProduce(APIstub, args)
} else if function == "queryAllProduces" {
return s.queryAllProduces(APIstub)
} else if function == "changeProduceStatus" {
return s.changeProduceStatus(APIstub, args)
}
return shim.Error("Invalid Smart Contract function name.")
}

For what you have a switch would be nice:
switch function {
case "queryProduce":
return s.queryProduce(APIstub, args)
case "initLedger":
return s.initLedger(APIstub)
case "createProduce":
return s.createProduce(APIstub, args)
case "queryAllProduces":
return s.queryAllProduces(APIstub)
case "changeProduceStatus":
return s.changeProduceStatus(APIstub, args)
}
Using a map would be inconvenient because not all your methods have the same signature, but you could use multiple maps.
Yet another solution could be to use reflection to call the methods, but again, handling the different arguments would be inconvenient. Reflection is also slower, not to mention you'd have to take care of not to allow calling methods not intended to be exposed. For an example, see Call functions with special prefix/suffix.

It is possible to express what you have as a map. The basic setup here is, no matter which path you go down, you get some function that you can call with no parameters, and it always returns the same type (error). I might explicitly pass the args in.
The high-level structure of this is to have a map of function names to functions, then call the selected function.
funcMap := map[string]func([]string) error{...}
funcName, args := APIstub.GetFunctionAndParameters()
f := funcMap[funcName]
if f == nil {
f = func(_ []string) error {
return shim.Error("Invalid Smart Contract function name.")
}
}
return f(args)
The map syntax gets kind of verbose
funcMap := map[string]func([]string) error{
"queryProduce": func(args []string) error {
return s.queryProduce(APIstub, args)
},
"initLedger": func(_ []string) error {
return s.initLedger(APIstub)
},
}
The map approach is better if you're ever going to call this in multiple places, or you want a separate validation step that some name would be defined if used, or if the actual list of functions is dynamic (you can add or remove things from the map at runtime). The inconsistent method signatures do introduce a complication and making everything consistent would help here (make functions like initLedger take an argument list even if it's unused).
In ordinary code I'd expect the switch form from #icza's answer to be more idiomatic.

Related

RoboHelp 2020: Need parameters for methods in RoboHelp scripting RoboHelp.exec(Name, parameters)

I have searched all over the internet and could not find anywhere that specified what parameters RoboHelp.exec() can accept when passing in RoboHelp.COMMAND.AUTHOR_DELETE_TOPIC_TOC
I have read this document: https://helpx.adobe.com/content/dam/help/en/pdf/RoboHelp-Scripting-Reference-2019.pdf. While it does define the available properties and the promise that they return it does not define the usage / specific parameters that methods (exec,getValue,setValue) accept.
Example code:
let callCount = 0;//without this count cbGetData will return 68 times. Not sure why this happens
function getData(key,topic,cb){
RoboHelp.exec(key,topic).then((value)=>{
cb(value);
});
}
function cbGetData(val){
if(callCount == 0)
{
//add your code here
alert(val);
}
callCount++;
}
getData(RoboHelp.COMMANDS.AUTHOR_DELETE_TOPIC_TOC,<WHAT_DO_I_PUT_HERE>,cbGetData)

How to conditionally run one of two functions with tokio::join?

I need to run 4 functions concurrently but one of them is different based on user input.
If I use "if-else" I get "if and else have incompatible types" due to Future.
The only way I see is to make a third function that selects from the other two, but it doesn't allow (to my knowledge) to run concurrently due to awaiting.
Another way is to make two different join! but that seems "code expensive".
What should I do in this situation?
tokio::join!(
self.func1(),
if self.flag() {
self.func2()
} else {
self.func3()
},
self.func4(),
self.func5()
);
The function signature is as follows:
pub async fn funcN(&self) -> Result<Vec<String>> {
You can use if inside an async block to produce a single future type from two:
tokio::join!(
func1(),
async {
if flag() {
func2().await
} else {
func3().await
}
},
func4(),
func5()
);
This has slightly different scheduling than the other answers: the flag() call is made part of the future rather than run immediately. If this is undesirable, you could put the boolean result in a variable beforehand.
Other than that, this is much like the Either approach, but can generalize to more than two choices.
The probably easiest way is to use a Box and dynamic dispatch. For example, this compiles:
tokio::join!(
func1(),
if flag() {
Box::pin(func2()) as Pin<Box<dyn Future<Output = _>>>
} else {
Box::pin(func3()) as Pin<Box<dyn Future<Output = _>>>
},
func4(),
func5()
);
Playground
You can use the futures::future::Either enum:
tokio::join!(
self.func1(),
if self.flag() {
Either::Left(self.func2())
} else {
Either::Right(self.func3())
},
self.func4(),
self.func5()
);
Playground

A function to read data from FireBase but requires Unit instead

I've made a function that calls on the FireBase database and will return a MutableList. However, when I try to make it return on a specific line, it says it requires a Unit instead of the MutableList.
fun firebaseCollect(key: String): MutableList<CustomList> {
var ref = FirebaseDatabase.getInstance().getReference(key)
var lessonList = mutableListOf<CustomList>()
ref.addValueEventListener(object: ValueEventListener{
override fun onCancelled(p0: DatabaseError?) {
}
override fun onDataChange(p0: DataSnapshot?) {
if (p0!!.exists()) {
lessonList.clear()
for (index in p0.children) {
val lesson = index.getValue(CustomList::class.java)
lessonList.add(lesson!!)
}
return lessonList
}
}
})
return lessonList
}
Type mismatch. Required: Unit, Found: MutableList< CustomList > is found at the first return lessonList since what I am asking for it to return is a MutableList not a Unit. I am confused as to why this happens. The last return would give an empty list. It is currently my first jab at FireBase and this is a practice I am doing. The rules for read and write have been set to public as well. How should I recode the function that I am able to return the data from FireBase into the function and passed back to the caller?
Firebase APIs are asynchronous. For your case, that means addValueEventListener returns immediately. Then, some time later, the listener you passed to it will be invoked with the data you're looking for. Your return statement in the callback doesn't actually return any data to the caller. In fact, you can't return anything from that callback. At the bottom of your function, when you return lessonList, you're actually returning an initially empty list to the caller, which may change later when the data finally arrives.
To get a better sense of how your code works, put log lines in various places, and see for yourself the order in which the code is invoked. You can read more about why Firebase APIs are asynchronous by reading this article. The bottom line is that you'll need to interact with the asynchronous APIs using asynchronous programming techniques. Don't try to make them synchronous.
Data is loaded asynchronously from Firebase. Once the data is fetched the method onDatachange() is invoked.
You are returning lessonList inside onDatachange(). Return type of onDatachange() is void(Unit in kotlin). This is the reason for the type mismatch error.
For returning the result from the method onDatachange() try this.

Shortest way to specify a return value expectation for a specific argument in Mockery

I want to create a Mock with a method that should return true for a specific argument, and false for any other argument.
I can achieve this with:
$this->myMock = Mockery::mock(MyClass::class);
$this->myMock->shouldReceive('myMethod')->with('my-argument')->andReturn(true);
$this->myMock->shouldReceive('myMethod')->andReturn(false);
But I was wondering if there's any shorter way to specify this, as I have to do this for many mocks, and looks like a lot of code for this simple purpose (note my properties/classes/methods/arguments names are quite longer than this example).
You can use Mockery's andReturnUsing-method. It takes a closure to calculate the return value by evaluating the provided argument. Should work like:
$this->mock
->shouldReceive('myMethod')
->andReturnUsing(function ($argument) {
if ($argument) {
return true;
}
return false;
});
I discovered I can use:
$this->myMock = Mockery::mock(MyClass::class);
$this->myMock->shouldReceive('myMethod')->passthru();
This will defer the calls to myMethod() to the real object, which will return true or false depending on the argument - this obviously doesn't do the same thing the code in the question does, but it does work in my scenario and it's quite shorter.

Is it possible to safely use Switch over FlowType union types (String Enums)?

In the following example, since I'm using matching over type of Message using the switch statement, I would like flow to recognise my incorrect case of 'ENUM_TYPO'. It currently doesn't.
type Message = 'BROADCAST_MESSAGE' | 'PRIVATE_MESSAGE';
const message: Message = 'BROADCAST_MESSAGE';
switch (message) {
case 'ENUM_TYPO':
// Do Broadcast
break;
default:
break;
}
As of v0.32.0, Flow does not complain about unreachable code, unless it's something like
// #flow
function foo() {
throw new Error();
return 123; // This will error
}.
However, consider the following code
// #flow
function foo(x: string): Object {
if (x === 123) {
return x;
}
return {};
}
Will currently will not error on this code. Flow does in fact notice that x === 123 will never be true. Inside the if block, Flow will refine the type of x to the empty type, since it doesn't believe that this code will ever be reached. That is why it doesn't complain about the return x statement.
One of the members of the Flow team is almost done with adding reachability analysis to Flow. Once this improvement lands (I'm guessing v0.34.0?), Flow will complain when it sees a conditional that it thinks will always fail. This will help you with your example, since switch statement cases are basically strict equality checks.

Resources