Any suggestion how to create a conditional mixin based on parameter existence?
For example I need to to verify that all the parameters are passed in order to perform something or not, for example:
.margin (#margintop:0,#marginbottom:0,#marginright:0,#marginleft:0) {
// if #marginright:0 or #marginleft:0 are passed do that...
// else...
}
1:
In general, when you need to generate different things for different number of arguments passed you don't need to use default argument values at all, e.g.:
.margin(#top, #bottom, #right, #left) {
/* right and left are passed */
}
.margin(#top, #bottom) {
/* right and left are not passed */
}
.margin() {
/* no arguments passed */
}
// etc.
Note that each of these mixins can reuse the others, for example .margin(#top, #bottom) can do something special for the "no right and left case" and then call .margin(#top, #bottom, 0, 0) to perform the main job.
2:
But if you still need these defaults for some reason you can use some special default value that can't be a valid margin, e.g. something like this:
.margin(#top: undefined, #bottom: undefined, #right: undefined, #left: undefined) {
.test-args();
.test-args() when (#right = undefined) {
/* right is not passed */
}
.test-args() when (#left = undefined) {
/* left is not passed */
}
.test-args()
when not(#right = undefined)
and not(#left = undefined) {
/* right and left are passed */
}
// etc.
}
3:
And the third option would be to use variadic arguments and test their count, but this one is the most verbose and dumb I guess:
.margin(#args...) {
.eval-args(length(#args)); // requires LESS 1.5.+
.eval-args(#nargs) {
// default values:
#top: not passed;
#bottom: not passed;
#right: not passed;
#left: not passed;
}
.eval-args(#nargs) when (#nargs > 0) {
#top: extract(#args, 1);
}
.eval-args(#nargs) when (#nargs > 1) {
#bottom: extract(#args, 2);
}
.eval-args(#nargs) when (#nargs > 2) {
#right: extract(#args, 3);
}
.eval-args(#nargs) when (#nargs > 3) {
#left: extract(#args, 4);
}
args: #top, #bottom, #right, #left;
}
Though it may probably have its pros in some special use-cases.
Related
The current release of Zig is 0.10.1 at the time of asking this question. The language is not yet stable and is subject to change.
How can I return an error as value from a failable function? I have tried the following, but it returns it as an error instead of returning it as a value:
fn foo_1() !anyerror {
// Returns outer error.
return error.Oops;
}
fn foo_2() !anyerror {
// Returns outer error.
var error_ = error.Oops;
return error_;
}
I would like to return it as value such that the following code to print out the error instead of propagating it when try is evaluated:
fn bar() !void {
var error_ = try foo();
std.debug.print("got error: {any}\n", .{ error_ });
}
I am asking this because I am trying to learn the language. I don't have a concrete use-case for this. However, I am curious if this is possible to do.
A similar related situation is to return an optional value which itself is optional (for example when forwarding the result of a function which returns an optional), but I was already able to find a solution for that:
fn baz_1() ??i32 {
// The outer optional is null.
return null;
}
fn baz_2() ??i32 {
// The inner optional is null.
var value: ?i32 = null;
return value;
}
Is something like that possible for errors as well?
No, it's not allowed in Zig. If you try you'll get an error like "error union with payload of error set type 'error{Def}' not allowed".
However, you can wrap the error in a struct:
const std = #import("std");
const ErrorError = error{
Abc,
};
const ErrorValue = error{
Def,
};
const WrappedError = struct {
err: ErrorValue,
};
fn foo() ErrorError!WrappedError {
return .{
.err = ErrorValue.Def,
};
}
test "returns error value" {
var bar = try foo();
std.debug.assert(bar.err == ErrorValue.Def);
}
error values can be declared with error{...} syntax. see https://ziglang.org/documentation/master/#Errors
pub const Error = error{Bar};
fn foo() error{Bar} {
return error.Bar;
}
// or anyerror
fn foo() anyerror {
return error.Bar;
}
I have a list of states, which are defined to be ordered by min to max. the sequence is the following:
Cancelled - complete - draft - reservation - reserved - ordered - confirmed
So the cancelled is the minimum state, and confirmed is the maximum state. I may have different instances with different states, so I use a for-each loop to run through all states, and select the minimum state present in the loop.
That is: if in a list I have states [complete, reserved, draft, ordered] I need to check all the values and select complete -as it appears to be the minimum state. OR
if I have [reserved, confirmed, ordered, draft, cancelled, confirmed, confirmed] I need to select the cancelled value, as it appears to be the minimum.
I am doing the following check, but it does not seem to be working:
string globstatus = " ";
foreach (var currentstatus in list)
{
if (currentstatus == "cancelled")
{
globstatus = "cancelled";
}
else
{
if (globstatus == "cancelled")
{
return globstatus;
}
else
{
if (currentstatus == "complete")
{
globstatus = "complete";
}
else
{
if (globstatus == "complete")
{
return globstatus;
}
else
{
if (currentstatus == "draft")
{
globstatus = "draft";
}
else
{
if (globstatus == "reservation")
{
return globstatus;
}
else
{
if (currentstatus == "reserved")
{
globstatus = "reserved";
}
else
{
if (globstatus == "ordered")
{
return globstatus;
}
else
{
if (currentstatus == "confirmed")
{
globstatus = "confirmed";
}
else
{
return currentstatus;
}
}
}
}
}
}
}
}
}
}
return globstatus;
What can be the best solution to achieve the desired behavior?
I find a rule of thumb helpful that if I need more than three levels of braces, I need to rethink my code. It's hard to follow, easy to make mistakes, and a nightmare to debug. I suggest that applies here - trying to follow the flow of what all those nested if..else statements is extremely difficult.
Using Enum
My preferred solution is to achieve this using an Enum, e.g.:
var list = new List<Status>
{
Status.Complete,
Status.Draft,
Status.Draft,
Status.Confirmed
};
var minStatus = (Status)list.Select(l => (int)l).Min();
// minStatus = Status.Complete
public enum Status
{
Cancelled,
Complete,
Draft,
Reservation,
Reserved,
Ordered,
Confirmed
}
How it works: by default Enums give each value a zero-based integer, i.e. Cancelled = 0, Complete = 1 and so on. You can override this with your own values if you wish (e.g. 1/2/4/8/16 if you want to combine multiple values).
I recommend using Enum types for things like this, rather than strings. It helps avoid typos, gives someone else looking at your code a clear understanding of how your program works and its flow, and represents hierarchy in a way in which simple strings don't. (For example - does 'complete' come before or after 'draft'? Without context, I imagine most people would say after, but in this case it comes before - that is much more obvious when using an Enum.)
Parse strings to Enum
However if the statuses have to be strings, you could parse them into an enum like so:
var stringList = new List<string>
{
"complete",
"draft",
"draft",
"confirmed",
"this will be ignored"
};
var statusList = new List<int>();
foreach (var str in stringList)
{
if(Enum.TryParse(typeof(Status), str, ignoreCase: true, out object? parsed) && parsed is Status status)
{
statusList.Add((int)status);
}
}
var minStatus = (Status)statusList.Min();
// minStatus = Status.Complete
However, if it's possible to refactor your code to use the Enum in the first place, that would be a better solution, and much quicker as parsing strings has an overhead that would be good to avoid.
I want to do something like below. In the Mono.fromCallable I run some block logic, then based on the value I either return Mono.empty() or the value so that it will either trigger the map or defaultIfEmpty.
Mono.fromCallable(() -> {
double number = Math.random();
if (number < 0.5) {
return Mono.empty();
}
return number;
})
.map(number -> 1)
.defaultIfEmpty(0)
This give an error since Mono.fromCallable expect a consistent return value. How do I adjust the code to make it work?
Although returning null is usually prohibited in Reactor APIs, it is a valid value that Callable may return, and Reactor handles it correctly by transforming into an empty Mono:
Mono.fromCallable(() -> {
double number = Math.random();
if (number < 0.5) {
return null;
}
return number;
})
I am doing a project for nand2tetris. We write a program in Jack and test it on VMEmulator. The class looks like this:
class List {
field int data;
field List next;
/* Creates a new List object. */
constructor List new(int car, List cdr) {
let data = car;
let next = cdr;
return this;
}
/* Disposes this List by recursively disposing its tail. */
method void dispose() {
if (~(next = null)) {
do next.dispose();
}
// Use an OS routine to recycle the memory held by this object.
do Memory.deAlloc(this);
return;
}
/* Prints the list*/
method void print() {
do Output.printString(" -> ");
do Output.printInt(data);
if (~(next = null)) {
do next.print();
}
return;
}
/* Inserts the argument in the right position of the list (ascending order)*/
method void insertInOrder(int ins){
var List prev, curr, insert;
let prev = this;
let curr = prev.getnext();
while (ins > prev.getdata()){
if (ins < curr.getdata()){
let insert = List.new(ins, curr);
do prev.setnext(insert);
}
else{
let prev = prev.getnext();
let curr = prev.getnext();
}
}
return;
}
/* Searches the argument in the list, if found, it returns the corresponding List object*/
method List find(int toFind){
var List temp;
var List equal;
var boolean found;
let temp = this;
let found = false;
while (~(next = null)){
if(toFind = temp.getdata()){
let equal = temp;
let found = true;
}
let temp = temp.getnext();
}
if (found){
return equal;
}
else{
return null;
}
}
method List getnext(){
return next;
}
method void setnext(List object){
let next = object;
return;
}
method int getdata(){
return data;
}
}
It has one private variable data and a pointer next. So I wrote getter and setter method to return those values. Other methods are fine only the getdata()method is incorrect. When it runs through the VMEmulator, it shows the error Out of segment space in List.getdata.3. This shows in the VMEmulator.
0function List.getdata0
1push argument0
2pop pointer0
3push this 0
4return
the error is at the 4th line return. When I change the Jack code, the same error is still at the 4th line.
What exactly is the problem in my getter method?
When you run a VM program on the VMEmulator you must first manually set the pointers to the various segments, otherwise you may get an "Out of segment space" error.
To understand the necessary settings, look at what the corresponding .tst file does. An alternative method is to insert the proposed code inside a function, since the function call automatically makes this type of setting.
You can get this error when you try to access member data of an object which is not constructed. Could it be that the List cdr in the constructor was not properly constructed?
How can I initialize a property with a custom setter?
For example, in my setter I make sure that the value is not negative.
class Foo(length: Int) {
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
}
However if I call it as Foo(-5) the exception doesn't call since setters aren't called when properties are initialized.
Another thing I tried was below, but then it seems wrong to set the length twice.
class Foo(length: Int) {
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
init {
this.length = length
}
}
Finally I thought about the code below, but that seems wrong since you are checking for the wrong value in two spots.
class Foo(length: Int) {
init {
if (length < 0) throw IllegalArgumentException("Can't be negative.")
}
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
}
Your second method is just about as clean as you can make it, although I would set the initial value to some constant like 0 rather than length. Then if you forget to assign length in an init block, you get a compiler warning that the constructor parameter is unused.
There is also a 'fourth' way (variation of your second, actually):
class Foo {
var length = 0 // You cannot even assign length here
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
// Having to use a warning suppression is the primary drawback of this 'fourth' way
#Suppress("ConvertSecondaryConstructorToPrimary")
constructor(length: Int) {
this.length = length
}
}
Apart from the express warning suppression annotation, this way the cleanest in my opinion, with no repetition and with minimal boilerplate.