Handling Exceptions and Other Errors with the Java SDK in Couchbase
This topic provides information on error handling when using the Couchbase Java SDK. It describes the general approach to Java exception handling with the SDK and the kinds of error handling you will want to consider during normal operations and in the case that the network or some part of your system infrastructure unexpectedly fails.
General Approach to Java Exceptions
All Couchbase specific exceptions are derived from CouchbaseException
.
All the other Exception types used are part of the JDK, including IllegalArgumentException
, TimeoutException
and others.
The following sections explain the exception types used by the SDK as well as how to perform proper error handling when they come up.
| The Javadocs contain a list of possible exceptions for each method called, which allows you to crossreference back and forth between the method called and the possible errors with explanation. |
Note that the transient
column in the reference tables refers to a short time interval where a retry with backoff makes sense from an application perspective and without the application interfering of some sort.
If you extend the time horizon long enough all errors can be considered transient (like creating a bucket that does not exist or fix a password), but it won’t be practical to wait in the application for it.
The following sections discuss different strategies to mitigate errors that might come up during operations.
Data Errors
Data errors are errors returned by the server because a certain data condition was not met. Data errors typically have very clear corrective paths.
Document Does not Exist
If a document is not found, then it has either not yet been created or has since been deleted. It is received on retrieval (get) operations (get a document), replace operations (replace a document that already exists), and remove operations (delete a document).
If this error is received when attempting to retrieve a document, then the item should either be created (if possible) or return an error to the user.
If this error is received when replacing a document, then it indicates an issue in the application state (perhaps you can raise an exception up the stack). If you do not care that the document exists, the upsert method may be used instead which ignores this case.
If receiving this error when removing an document, it may safely be ignored: not-found on remove essentially means the item is already removed.
The Not Found error is returned by the server.
Document Already Exists
The insert operation requires that the document does not exist yet; it is intended to create a new unique record (think about inserting a "new user ID"). This error is returned by the server when a document already exists. Applications at this point should probably return an error up the stack to the user (when applicable); for example indicating that a new account could not be registered with the given user name, since it already exists.
CAS Mismatch
A CAS mismatch error is returned when an operation was executed with a CAS value (supplied by the application) and the CAS value passed differs from the CAS value on the server. The corrective course of action in this case is for the application to re-try the read-update cycle as explained in detail in the CAS documentation.
Document too Big
If the maximum content size is larger than 20MB the server responds with an error noting that it can’t store it since it is too big. This error is not transient and must be raised up the stack since it likely indicates an application error that creates too large document contents.
Transient and Resource Errors
These errors may be received because of resource starvation.
Temporary Failure
This error is received when the server is temporarily inhibiting an error that doesn’t allow it to respond successfully. For example during mutations when the cluster node has run out of memory or is currently warming up. Its disk and replication queues are full and must wait until items in those queues are stored and replicated before it can begin receiving new operations.
While this condition is rare, it may happen under massively concurrent writes from clients and a limited memory allocation on the server.
The short-term corrective action for this error is to throttle and slow down the application, giving Couchbase some time for pending operations to complete (or to complete warmup) before issuing new operations. The long term corrective action is to increase memory capacity on the cluster, either by adding more RAM to each node, or by adding more nodes. The above example shows (in pseudo-code) how to handle a temporary failure error with a linear backoff.
MAX_RETRIES = 5
BASE_DELAY = 50 // milliseconds
current_attempts = 1
do {
try {
bucket.upsert(id, document)
break
} catch (TemporaryFailure error) {
sleep(BASE_DELAY * current_attempts)
}
} while (++current_attempts != MAX_RETRIES)
Out Of Memory
This error indicates a severe condition on the server side and probably needs to be logged and/or signaled to monitoring systems. There is not much the application can do there to mitigate the situation other than backing off significantly and waiting until the server side memory shortage is resolved.
Generic Error Types
All couchbase specific exceptions inherit from the CouchbaseException
.
One exception that you want to plan for is the RequestCancelledException
.
It comes up if a request is in-flight but the socket gets closed or the SDK can’t schedule the request for longer than the maximum configurable lifetime.
In any event, if the operation is idempotent it makes sense to retry with backoff, but if a mutation operation has been canceled extra care needs to be taken to make sure state is not lost.
For example, if a replace
operation got canceled it makes sense to check again with a get
to see if it took place or not and then react based on the result.
This exception is transient since the underlying socket might be reopened at some point.
Finally the BackpressureException
raised by the SDK when the sender of requests (your application threads) are overwhelming the consumer (the SDK).
It mostly happens in purely asynchronous environments but can also happen in blocking scenarios.
If you receive such an exception it is always a wise idea to slow down the request rate or bubble up the error in a fail fast manner to the caller.
This exception is almost always transient since once the pressure is reduced the SDK will go back into a stable state where the request completion rate equals or is higher than the incoming request rate.
| Name | Transient | Description |
|---|---|---|
|
depends |
Top level Couchbase exception type |
|
yes |
Request canceled while in-flight on the socket or couldn’t be scheduled for longer than the max lifetime period. |
|
yes |
If the SDK is overwhelmed with the incoming request rate from the application for some reason. |
Connection Management Errors
If you are trying to open a Bucket
and it does not exist you get a BucketDoesNotExistException
.
If it has a different password compared to the supplied one you get a InvalidPasswordException
instead.
If you are performing operations on a Cluster
which does not support it, for example you don’t have the query service enabled and you perform a N1QL operation, you get a ServiceNotAvailableException
.
When running into errors during bootstrap when SSL is enabled, you see a SSLException
wrapped in a ConfigurationExeption
.
The ConfigurationException
is a more generic error that reports that something has gone wrong during bootstrap with the configuration.
Finally if you are performing an operation on a closed Bucket you get a BucketClosedException
.
| Name | Transient | Description |
|---|---|---|
|
no |
If the bucket does not exist when trying to remove/open it.
Note that with Server 4.5 and later, the server will also trigger a |
|
no |
If the bucket password is different than the one provided. |
|
no |
If a service is not enabled on at least one of the cluster nodes when trying to use it. |
|
no |
Issues with SSL/Encryption during bootstrap. |
|
no |
All kinds of configuration errors during bootstrap. |
|
no |
If the bucket is already closed when trying to use it. |
Bucket Operation Errors
When a Document is mutated through the key value API a couple exceptions could be raised depending on the state of that Document on the cluster:
| Name | Transient | Description |
|---|---|---|
|
no |
If the document with the given ID already exists (i.e. during an insert). |
|
no |
If the document with the given ID does not exist (i.e. during a replace). |
|
no |
The provided CAS on replace does not match with the server (someone else updated it in the meantime). |
|
no |
The payload is larger than the maximum size (20MB). |
If durability requirements (ReplicateTo
, PersistTo
) are used, in addition the following exceptions can happen:
| Name | Transient | Description |
|---|---|---|
|
depends |
The durability requirement for this operation can’t be met temporarily or persistently. |
|
no |
When MutationTokens enabled, signifies a lost mutation during hard fail over. |
|
no |
When MutationTokens disabled, signifies concurrent updates on the observed document. |
When a getFromReplica
is issued you need to watch out for the following :
| Name | Transient | Description |
|---|---|---|
|
yes |
The replica is currently not available (i.e. after a fail over before rebalance). |
|
no |
The replica is not configured on the bucket itself. |
When you are trying to lock a document you may get the following:
| Name | Transient | Description |
|---|---|---|
|
yes |
The server reports a temporary failure and it is very likely to be lock-related (like an already locked key or a bad CAS used for unlock). |
During a View request the following exception can happen:
| Name | Transient | Description |
|---|---|---|
|
no |
The view does not exist on the server (or the design document where it should belong) or is not published. |
Note that for Views it is also important to check the isSuccess()
method as well as to check the error()
method since it is possible that errors during streaming may come up.
See the section on View Queries for detailed information.
Similarly, when a N1QL request is issued watch out for the following:
| Name | Transient | Description |
|---|---|---|
|
depends |
Encloses various specific errors during N1QL query execution. |
|
no |
Error with execution or preparation of a named prepared statement. |
Note that for N1QL it is also important to check the finalSuccess()
method as well as to check the errors()
method since it is possible that errors during streaming may come up.
See the section on N1QL Queries for detailed information.
Finally, the following generic exceptions can happen in general when performing data related operations:
| Name | Transient | Description |
|---|---|---|
|
no |
Error while encoding or decoding Document content. |
|
yes |
Couchbase Server is currently out of memory. |
|
yes |
Couchbase Server reports a temporary failure of some kind. |
Sub-Document Operation Errors
When performing Sub-Document operations there is a different set of exceptions to look out for compared to regular key value based operations. Most of them affect how the paths inside the Document is used.
| Name | Transient | Description |
|---|---|---|
|
no |
Exception denoting that at least one error occurred when applying multiple mutations. |
|
no |
The path is too deep to parse. Depth of a path is determined by how many levels it contains. |
|
no |
A number value inside the document is too big. |
|
no |
The part of the document to store is not valid JSON. |
|
no |
The provided value cannot be inserted at the given path. |
|
no |
The provided path is invalid. |
|
no |
The proposed value would make the document too deep to parse. |
|
no |
The path does not exist in the document. |
|
no |
When a path exists but it shouldn’t, like in the insert case. |
|
no |
The document is too deep to parse. |
|
no |
The delta on counter operations is invalid. |
|
no |
The path structure conflicts with the document structure. |
Bucket and Index Management Errors
When you are manipulating buckets (that is, inserting or removing them) you can run into both BucketAlreadyExistsException
and BucketDoesNotExistException
.
If you perform a flush operation on a bucket but it is disabled on the server side, the SDK raises a FlushDisabledException
.
While performing operations on N1QL indexes (GSI), similar to bucket management either a IndexDoesNotExistException
or a IndexAlreadyExistsException
can be raised during manipulation.
In addition if you are waiting on an index a IndexesNotReadyException
is raised if the index is not ready yet.
During design document manipulation a DesignDocumentAlreadyExistsException
is thrown if the design document already exists and one with the same name is inserted.
| Name | Transient | Description |
|---|---|---|
|
no |
The bucket already exists when trying to create it. |
|
no |
The bucket does not exist when trying to remove/open it. |
|
no |
Bucket has flush disabled on the server side, but triggered on the SDK. |
|
no |
The N1QL GSI Index does not exist. |
|
no |
The N1QL GSI Index already exists when trying to create it. |
|
yes |
N1QL GSI indexes are watched but take longer to become ready than after the amount of attempts retried. |
|
no |
The design document already exists when trying to insert it. |
Error Handling - Logging
It is always important to log errors, but even more so in the case of reactive applications. Because of the event driven nature, stack traces get harder to look at, and caller context is sometimes lost.
It is also recommended to configure your logger to include absolute timestamps. While this is always a good idea, if combined with good logging throughout the application it makes it easier to debug error cases and see later what was going on inside your reactive application.
RxJava provides operators for side effects (additional behavior that doesn’t change the items flowing through the Observable stream), which should be used to log errors. Of course, you can also put logging into the error handlers, but readability is increased if the logging is put explicitly as a side effect.
Observable
.error(new Exception("I'm failing"))
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// I'm an explicit side effect
// use a proper logger of your choice here
LOGGER.warn("Error while doing XYZ", throwable);
}
})
.subscribe();
You can also utilize the various other side-effect operators for general logging (doOnNext
, doOnCompleted
).
If you don’t want to have different side effects for the same logging operation, you can use doOnEach
.
It will be called for both errors and next events with a Notification object that denotes what kind of event is being processed.
Error Handling - Failing
Failing is the easiest way to handle errors - because you don’t. While most of the time you want more sophisticated error handling strategies (as discussed later), sometimes you just need to fail. It makes no sense for some errors to be retried, either because they are not transient or because you already tried everything to make it work and it still keeps failing.
In error-resilient architectures, you want to do everything to keep the error contained. However, if the containment is not able to handle the error it needs to propagate it to a parent component that (possibly) can.
In the asynchronous case, errors are events like every other for your subscribers.
Once an error happens, your Subscriber
is notified in the method onError(Throwable)
, and you can handle it the way you want to.
Note that by Observable
contract, after the onError
event, no more onNext
events will happen.
Observable
.error(new Exception("I'm failing"))
.subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
System.err.println("Got Error: " + e);
}
@Override
public void onNext(Object o) {
}
});
It is always a good idea to implement error handling.
In the synchronous case, every error is converted into an Exception and thrown so that you can use regular try
/catch
semantics.
try {
Object data = Observable.error(new Exception("I'm failing"))
.toBlocking()
.single();
} catch(Exception ex) {
System.err.println("Got Exception: " + ex);
}
If you do not catch the Exception, it will bubble up:
Exception in thread "main" java.lang.RuntimeException: java.lang.Exception: I'm failing
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:482)
at rx.observables.BlockingObservable.single(BlockingObservable.java:349)
Error Handling - Retry
Retrying operations is a common technique to ride over transient errors. It should not be used for non-transient errors because it will only put a load onto the system without the chance to resolve the error.
In practice, the following retry strategies can be applied when a transient error is discovered:
-
Retry immediately.
-
Retry with a fixed delay.
-
Retry with a linearly increasing delay.
-
Retry with an exponentially increasing delay.
-
Retry with a random delay.
Unless you have a very good reason not to, always apply a maximum number of attempts and then escalate the error. Systems stuck in infinite retry loops can cause issues that are very hard to debug. It’s better to fail and propagate at some point.
Also, we recommend that you use asynchronous retry even if you are blocking at the very end.
Retrying in the asynchronous Observables
is way more resource efficient and also the only sane way to handle multiple operation steps (and bulk operations) under a single timeout.
The Java SDK comes with a RetryBuilder
, a utility class to describe retries with a fluent API.
- Retry without delay
-
Let’s get one thing straight right away: immediately retrying is almost never a good idea. Instead of resolving the error more quickly, it will put more pressure onto the retried system, and there is a good chance it will make resolving errors harder.
One good reason to do so is if you have a specific operation with a very short timeout that you want to keep retrying for a small, fixed amount of times and if it still does not work, fail fast.
If you have the feeling you need to retry very quickly, you can also apply a very slight increasing delay to, at least, release some pressure from the target system.
RxJava provides the
retry
operator to resubscribe to the sourceObservable
immediately once it fails (an error event happens). Three flavors are available:-
retry()
: Instantly retry as long as the sourceObservable
emits an error. It is strongly recommend not to use this operator. -
retry(long count)
: Instantly retry as long as the sourceObservable
emits an error or the max count is reached. If the count is reached, the Observable will not be resubscribed, but the error is propagated down the stream. This operator is recommended for use. -
retry(Func2<Integer, Throwable, Boolean> predicate)
: Instantly retry as long as the predicate returns true. Arguments to the predicate are the number of tries, as well as the exception type.
Since the
predicate
method provides the most flexibility, it is recommended to use it. If you only want to handle a specific exception and retry a maximum ofMAX_TRIES
times, you can do it like this:+
Observable.error(new CASMismatchException()) .retry(new Func2<Integer, Throwable, Boolean>() { @Override public Boolean call(Integer tries, Throwable throwable) { return (throwable instanceof CASMismatchException) && tries < MAX_TRIES; } }) .subscribe();
+ Try replacing
CASMismatchException
with something else and you will see that it does not try to retry, but rather propagates the error downstream. You can use this technique to handle specific errors differently by adding more retry operators in the pipeline.+ Using the
retry
withpredicate
also allows you to log the number of retries for a specific error. If you use thedoOnError
for logging, it’s harder to log the number of retries.+ The synchronous equivalent to the latest code looks like this:
+
int tries = 0; while(true) { tries++; try { pretendWorkThatMaybeThrows(); // does some work and maybe throws break; } catch(Throwable throwable) { if (!(throwable instanceof CASMismatchException) || tries >= MAX_TRIES) { throw throwable; // rethrow exceptions } } }
-
- Retry with delay
-
When applying a Retry with delay, the main question you need to ask yourself is: how often and how long is it feasible to retry before giving up (and escalate the error). Using this retry option depends on the type of operation, use case, and SLA that the application requires, but the techniques are the same.
RxJava provides the
retryWhen
operator, which allows you more flexibility with the actions performed as well as when the resubscription is happening. This section covers the different delay approaches based on this operator.Here is the contract for
retryWhen
that you should always keep in mind:-
It is called when an error on the source
Observable
happens. -
The function provided will be called with an
Observable
containing this error. -
If you make this
Observable
error, it is propagated downstream (without retrying). -
If you make this
Observable
complete, it is propagated downstream (without retrying). -
If you make this
Observable
callonNext
, a retry will happen.
Since the version 2.1.0 the Java SDK comes with the
RetryBuilder
, a helper to describe when and how to retry: only on certain classes of exceptions, max 5 attempts, the exponential delay between attempts, and so on. The result of this builder (calling build()
) can be used with RxJava’sretryWhen
operator directly:+
Observable.error(new IllegalStateException()) .retryWhen( RetryBuilder.anyOf(IllegalStateException.class).max(6).delay(Delay.linear(TimeUnit.SECONDS)).build() );
+ This code will ultimately fail after 6 additional attempts. It would fail fast if the source returns an error with something other than an
IllegalStateException
during retries. Each attempt will be made with an increasing delay, which grows linearly (1 second, then 2, 3, 4). If an exception occurs that is not managed by the handler, it is propagated as is, allowing you to chain such handlers.+ If the maximum number of attempts is reached, the last exception that occurred is propagated, wrapped in a
CannotRetryException
. This helper allows to write retry semantics more easily, but in this section it is explained how to write them from scratch.+ The easiest approach is the fixed delay. The source
Observable
will be resubscribed after a specified amount of time and for a fixed maximum number of times.+ Because the nested logic is a bit harder to understand in the first place, let’s talk through it step by step and then put it together.
+ Our
retryWhen
function is called every time an error happens on the sourceObservable
. If we wanted to try forever every second, it could look like this:+
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<?extends Throwable> errorNotification) { return errorNotification.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { return Observable.timer(1, TimeUnit.SECONDS); } }); } })
+ We
flatMap
our notificationObservable
and utilize theObservable#timer
to defer emitting a new event for a second. Since we need to stop at some point, after a given number of tries, we can utilize theObservable#zipWith
operator to zip our error stream together with a range where we specify the number of tries we want to allow. Zipping has the nice side-effect that once one of theObservable
is completed, the resultingObservable
will also be complete, which triggers our Rule 4 from above.+ The modified version looks like this:
+
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> errorNotification) { return errorNotification.zipWith(Observable.range(1, 4), new Func2<Throwable, Integer, Integer>() { @Override public Integer call(Throwable throwable, Integer attempts) { return attempts; } }) .flatMap(new Func1<Integer, Observable<?>>() { @Override public Observable<?> call(Integer attempts) { return Observable.timer(1, TimeUnit.SECONDS); } }); } }
+ Technically, we don’t need the zip function here because we ignore it later on, but it is required for the
zipWith
operator to work. We use theObservable#range
operator to create anObservable
that emits three events and then completes, so we will never end up with more retries.+ There is one more enhancement needed: the code as it stands there will swallow the originating exception when moving on, which is not good because it should be propagated if it can’t be handled in this code block.
+ The following code is modified so that the function of
zipWith
returns not only the attempted count but also the throwable, so that Couchbase Server has access to it in theflatMap
method. For this, the Java client has a genericTuple
the server can utilize. In theflatMap
, Couchbase Server checks for the number of attempts, and if it is over the threshold, it re-throws the exception. Keep in mind that you need to changeObservable#range
call toMAX_ATTEMPTS+1
, to give your code a chance to be called again one final time.+
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> errorNotification) { return errorNotification.zipWith(Observable.range(1, 5), new Func2<Throwable, Integer, Tuple2>Throwable, Integer>>() { @Override public Tuple2<Throwable, Integer> call(Throwable throwable, Integer attempts) { return Tuple.create(throwable, attempts); } }).flatMap(new Func1<Tuple2<Throwable, Integer>, Observable<?>>() { @Override public Observable<?> call(Tuple2<Throwable, Integer> attempt) { if (attempt.value2() == 3) { return Observable.error(attempt.value1()); } return Observable.timer(1, TimeUnit.SECONDS); } }); } })
+ If you want to enhance it even further, you can add one more
if()
clause in theflatMap
to see if the throwable that is passed down is actually the one we want to retry.+ Functionality like this is a great candidate to be generic and encapsulated, so that’s what we did with
RetryBuilder
. If you are already using Java 8, the code becomes more condensed as well:+
.retryWhen(notification -> notification.zipWith(Observable.range(1, 5), Tuple::create) .flatMap(att -> att.value2() == 3 ? Observable.error(att.value1()) : Observable.timer(1, TimeUnit.SECONDS)))
+ Here are the variations for linear, exponential and random delays:
+ Linear:
+
// Utilizes the number of attempts for the number of seconds to wait .retryWhen(notification -> notification .zipWith(Observable.range(1, 5), Tuple::create) .flatMap(att -> att.value2() == 3 ? Observable.error(att.value1()) : Observable.timer(att.value2(), TimeUnit.SECONDS)) )
+ Exponential:
+
// Uses the timer with 2^attempts to generate exponential delays .retryWhen(notification -> notification .zipWith(Observable.range(1, 5), Tuple::create) .flatMap(att -> att.value2() == 3 ? Observable.error(att.value1()) : Observable.timer(1 << att.value2(), TimeUnit.SECONDS)) )
+ Random:
+
// Random between 0 and 5 seconds to retry per attempt .retryWhen(notification -> notification .zipWith(Observable.range(1, 5), Tuple::create) .flatMap(att -> att.value2() == 3 ? Observable.error(att.value1()) : Observable.timer(new Random().nextInt(5), TimeUnit.SECONDS)) )
+ With the synchronous code, there are not many options other than using
Thread.sleep()
to keep the current thread waiting until the loop is allowed to proceed:+
// Linear Backoff int tries = 0; while(true) { tries++; try { pretendWorkThatMaybeThrows(); // does some work and maybe throws break; } catch(Throwable throwable) { if (!(throwable instanceof CASMismatchException) || tries >= MAX_TRIES) { throw throwable; // rethrow exceptions } Thread.sleep(TimeUnit.SECONDS.toMillis(tries)); }
+ You can then use the same approaches as with the asynchronous ones on the
Thread.sleep()
time to accommodate for a static, linear, exponential or random delay. -
- Retry for some exceptions
-
Using
RetryBuilder
allows a more nuanced approach, letting you mandate different responses to different exceptions, and leading to code which can be easier to reason about - like the two examples below. This first example configures the Retry Builder so that when an error happens during a document fetch, it retries up to 20 times and waits 100 ms in between attempts. But it only retries on the two exceptions given, everything else is propagated downstream. Note how the 100 * 20 ms = 2s aligns with the timeout provided; this doesn’t have to be, but it makes sense to align it.bucket.async() .get("document_id") .retryWhen(RetryBuilder .anyOf(BackpressureException.class, RequestCancelledException.class) .delay(Delay.fixed(100, TimeUnit.MILLISECONDS)) .max(20) .build() ) .timeout(2, TimeUnit.SECONDS) .toBlocking() .single();
This example can be modified to produce the variationbelow, where different retry strategies are used for different exception types. A request cancellation might be retried immediately (1ms), whereas backpressure signalling overload may need a more gradual back off, with an exponential strategy:
bucket.async() .get("document_id") .retryWhen(RetryBuilder .anyOf(BackpressureException.class) .delay(Delay.exponential(TimeUnit.MILLISECONDS, 1000, 1)) .max(Integer.MAX_VALUE) .build() ) .retryWhen(RetryBuilder .anyOf(RequestCancelledException.class) .delay(Delay.fixed(1, TimeUnit.MILLISECONDS)) .max(2) .build() ) .timeout(2, TimeUnit.SECONDS) .toBlocking() .single();
Note the following values (and their defaults), which we override above:
-
max attempts => 1
-
default retry delay => constant 1ms
-
anyOf errors => all errors are retried by default
-
Error Handling - Fallback
Instead of (or in addition to) retrying, another valid option is falling back to either a different Observable
or a default value.
RxJava provides you with different operators, prefixed with onError*()
:
-
onErrorReturn(Func1<Throwable, T>)
: It is called when the sourceObservable
errors and allows to return custom data instead. -
onErrorResumeNext(Observable<?>)
: It is called when the sourceObservable
errors and allows to resume transparently with a different Observable. -
onErrorResumeNext(Func1<Throwable, Observable<?>)
: It is called when the sourceObservable
errors and allows to transparently resume with anObservable
(based on a specificThrowable
).
You should use the onErrorReturn
if you want to fallback to static data quickly.
For example:
Observable.<String>error(new Exception("I failed"))
.onErrorReturn(new Func1<Throwable, String>() {
@Override
public String call(Throwable throwable) {
// You could return data based on the throwable as well
return "Default";
}
})
.subscribe();
If you only want to return default values based on a specific exception or even call another Observable
as fallback, onErrorResumeNext
is what you’re looking for.
Observable.<String>error(new TimeoutException("I failed"))
.onErrorResumeNext(new Func1<Throwable, Observable<? extends String>>() {
@Override
public Observable<? extends String> call(Throwable throwable) {
if (throwable instanceof TimeoutException) {
return Observable.just("Default");
}
// Forward anything other than the TimeoutException
return Observable.error(throwable);
}
})
.subscribe();
If you just want to fallback onto another Observable
that you have in scope without caring about the Exception, you can use the other onErrorResumeNext()
overload.
For example, this loads data from all replicas if the get()
call did not succeed with the Java SDK:
bucket.async()
.get("id")
.onErrorResumeNext(bucket.async().getFromReplica("id", ReplicaMode.ALL))
.subscribe();
Synchronous fallbacks can be implemented by conditionally setting the default in the catch
clause:
String value;
try {
value = pretendWorkThatMaybeThrows();
} catch(Exception ex) {
value = "Default";
}
Here is the gotcha: this synchronous example only works great if the fallback is static.
If you need to fallback into another database call, for example, you quickly get into nested error handling and timeouts are a pain to handle (since they start to accumulate for every synchronous call).
It is recommended to use asynchronous fallbacks and then block at the very end through toBlocking().single()
or equivalents.


Class TraceExtensions
This helper class provides additional methods for tracing purposes
Inheritance
Inherited Members
Namespace: NMF.Transformations
Assembly: NMF.Transformations.dll
Syntax
public static class TraceExtensions
Methods
| Improve this Doc View SourceFindAll<TOut>(ITransformationTrace, Type[])
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> FindAll<TOut>(this ITransformationTrace trace, Type[] inputTypes)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Type[] | inputTypes | The input types of the trace request |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output that is returned by the transformation rule |
FindAll<TIn, TOut>(ITransformationTrace)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> FindAll<TIn, TOut>(this ITransformationTrace trace)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input parameter type of the transformation rule |
| TOut | The output that is returned by the transformation rule |
FindAll<TIn1, TIn2, TOut>(ITransformationTrace)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> FindAll<TIn1, TIn2, TOut>(this ITransformationTrace trace)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The first input parameter type of the transformation rule |
| TIn2 | The second input parameter type of the transformation rule |
| TOut | The output that is returned by the transformation rule |
FindAllIn<TOut>(ITransformationTrace, TransformationRuleBase<TOut>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<TOut> FindAllIn<TOut>(this ITransformationTrace trace, TransformationRuleBase<TOut> rule) where TOut : class
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TOut> | rule | The transformation rule |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TOut |
FindAllIn<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<TOut> FindAllIn<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TIn | |
| TOut |
FindAllIn<TIn1, TIn2, TOut>(ITransformationTrace, TransformationRuleBase<TIn1, TIn2, TOut>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<TOut> FindAllIn<TIn1, TIn2, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn1, TIn2, TOut> rule)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn1, TIn2, TOut> | rule | The transformation rule |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | |
| TIn2 | |
| TOut |
FindInWhere<TOut>(ITransformationTrace, TransformationRuleBase<TOut>, Predicate<TOut>)
Finds all outputs of computations of from the specified source type to the specified target type that match the given filter
Declaration
public static IEnumerable<TOut> FindInWhere<TOut>(this ITransformationTrace trace, TransformationRuleBase<TOut> rule, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TOut> | rule | The transformation rule the object was transformed with |
| System.Predicate<T><TOut> | filter | The filter that should be applied to the transformation outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all suitable outputs |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output type of the transformation rule |
FindInWhere<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, Predicate<TOut>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> FindInWhere<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| System.Predicate<T><TOut> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type parameter of the transformation rule |
| TOut | The output that is returned by the transformation rule |
FindInWhere<TIn1, TIn2, TOut>(ITransformationTrace, TransformationRuleBase<TIn1, TIn2, TOut>, Predicate<TOut>)
Finds all outputs of computations of the given transformation that match the given filter
Declaration
public static IEnumerable<TOut> FindInWhere<TIn1, TIn2, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn1, TIn2, TOut> rule, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn1, TIn2, TOut> | rule | The transformation rule the object was transformed with |
| System.Predicate<T><TOut> | filter | The filter that should be applied to the transformation outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all suitable outputs |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The type of the first transformation argument |
| TIn2 | The type of the second transformation argument |
| TOut | The output type of the transformation rule |
FindWhere<TOut>(ITransformationTrace, Type[], Predicate<TOut>)
Finds all outputs of computations of from the specified source type to the specified target type that match the given filter
Declaration
public static IEnumerable<TOut> FindWhere<TOut>(this ITransformationTrace trace, Type[] inputTypes, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Type[] | inputTypes | The input types for the transformation rule |
| System.Predicate<T><TOut> | filter | The filter that should be applied to the transformation outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all suitable outputs |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output type of the transformation rule |
FindWhere<TIn, TOut>(ITransformationTrace, Predicate<TOut>)
Finds all outputs of computations of from the specified source typpe to the specified target type that match the given filter
Declaration
public static IEnumerable<TOut> FindWhere<TIn, TOut>(this ITransformationTrace trace, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Predicate<T><TOut> | filter | The filter that should be applied to the transformation outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all suitable outputs |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type of the transformation rule |
| TOut | The output type of the transformation rule |
FindWhere<TIn1, TIn2, TOut>(ITransformationTrace, Predicate<TOut>)
Finds all outputs of computations of from the specified source type to the specified target type that match the given filter
Declaration
public static IEnumerable<TOut> FindWhere<TIn1, TIn2, TOut>(this ITransformationTrace trace, Predicate<TOut> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Predicate<T><TOut> | filter | The filter that should be applied to the transformation outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all suitable outputs |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The type of the first transformation argument |
| TIn2 | The type of the second transformation argument |
| TOut | The output type of the transformation rule |
GetOrCreateUserItem<TValue>(ITransformationContext, object, Func<TValue>)
Gets or creates the user item with the specified key
Declaration
public static TValue GetOrCreateUserItem<TValue>(this ITransformationContext context, object key, Func<TValue> valueCreator = null)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationContext | context | The transformation context |
| object | key | The key for the user item |
| System.Func<TResult><TValue> | valueCreator | A method that creates the default value if the user item does not yet exist or null, if no user item should be created |
Returns
| Type | Description |
|---|---|
| TValue | The user item with the specified key |
Type Parameters
| Name | Description |
|---|---|
| TValue | The type of the user item |
Resolve<TOut>(ITransformationTrace, object[])
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static TOut Resolve<TOut>(this ITransformationTrace trace, object[] input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| object[] | input | The input arguments |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output that is returned by the transformation rule |
Resolve<TIn, TOut>(ITransformationTrace, TIn)
Trace the output of the computation that transformed the given input into a desired output
Declaration
public static TOut Resolve<TIn, TOut>(this ITransformationTrace trace, TIn input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TIn | input | The input argument |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The desired output type |
Resolve<TIn1, TIn2, TOut>(ITransformationTrace, TIn1, TIn2)
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static TOut Resolve<TIn1, TIn2, TOut>(this ITransformationTrace trace, TIn1 input1, TIn2 input2)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TIn1 | input1 | The first input argument |
| TIn2 | input2 | The second input argument |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The first input type that is looked for |
| TIn2 | The second input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveIn(ITransformationTrace, GeneralTransformationRule, object[])
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static object ResolveIn(this ITransformationTrace trace, GeneralTransformationRule rule, object[] input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| GeneralTransformationRule | rule | The rule that transformed the argument |
| object[] | input | The input arguments |
Returns
| Type | Description |
|---|---|
| object | The output of the computation with the specified input argument or null, if there is none such |
ResolveIn<TOut>(ITransformationTrace, TransformationRuleBase<TOut>, object[])
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static TOut ResolveIn<TOut>(this ITransformationTrace trace, TransformationRuleBase<TOut> rule, object[] input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TOut> | rule | The transformation rule the object was transformed with |
| object[] | input | The input arguments |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output that is returned by the transformation rule |
ResolveIn<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, TIn)
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static TOut ResolveIn<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, TIn input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| TIn | input | The input argument |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveIn<TIn1, TIn2, TOut>(ITransformationTrace, TransformationRuleBase<TIn1, TIn2, TOut>, TIn1, TIn2)
Trace the output of the computation that transformed the given input with the given transformation type
Declaration
public static TOut ResolveIn<TIn1, TIn2, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn1, TIn2, TOut> rule, TIn1 input1, TIn2 input2)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn1, TIn2, TOut> | rule | The transformation rule the object was transformed with |
| TIn1 | input1 | The first input argument |
| TIn2 | input2 | The second input argument |
Returns
| Type | Description |
|---|---|
| TOut | The output of the computation with the specified input argument or null, if there is none such |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The first input type that is looked for |
| TIn2 | The second input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveInWhere(ITransformationTrace, GeneralTransformationRule, Predicate<ITraceEntry>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<object> ResolveInWhere(this ITransformationTrace trace, GeneralTransformationRule rule, Predicate<ITraceEntry> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| GeneralTransformationRule | rule | The transformation rule that was used to transform the outputs |
| System.Predicate<T><ITraceEntry> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><object> | All outputs of computations with suitable input arguments or null, if there are none |
ResolveInWhere<TOut>(ITransformationTrace, TransformationRuleBase<TOut>, Predicate<object[]>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveInWhere<TOut>(this ITransformationTrace trace, TransformationRuleBase<TOut> rule, Predicate<object[]> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TOut> | rule | The transformation rule the object was transformed with |
| System.Predicate<T><object[]> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output that is returned by the transformation rule |
ResolveInWhere<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, Predicate<TIn>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveInWhere<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, Predicate<TIn> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| System.Predicate<T><TIn> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveInWhere<TIn1, TIn2, TOut>(ITransformationTrace, TransformationRuleBase<TIn1, TIn2, TOut>, Func<TIn1, TIn2, bool>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<TOut> ResolveInWhere<TIn1, TIn2, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn1, TIn2, TOut> rule, Func<TIn1, TIn2, bool> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn1, TIn2, TOut> | rule | The transformation rule |
| System.Func<T1, T2, TResult><TIn1, TIn2, bool> | filter | A filter that is to be applied on the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | |
| TIn2 | |
| TOut |
ResolveMany<TIn, TOut>(ITransformationTrace, TIn)
Trace the output of the computation that transformed any input that matches the filter into the desired type
Declaration
public static IEnumerable<TOut> ResolveMany<TIn, TOut>(this ITransformationTrace trace, TIn input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TIn | input | An input argument to look up multiple results |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The desired output type |
ResolveMany<TIn, TOut>(ITransformationTrace, params TIn[])
Trace the output of the computation that transformed any input that matches the filter into the desired type
Declaration
public static IEnumerable<TOut> ResolveMany<TIn, TOut>(this ITransformationTrace trace, params TIn[] list)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TIn[] | list | A list of allowed input arguments |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The desired output type |
ResolveMany<TIn, TOut>(ITransformationTrace, IEnumerable<TIn>)
Trace the output of the computation that transformed any input that matches the filter into the desired type
Declaration
public static IEnumerable<TOut> ResolveMany<TIn, TOut>(this ITransformationTrace trace, IEnumerable<TIn> list)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Collections.Generic.IEnumerable<T><TIn> | list | A list of allowed input arguments |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The desired output type |
ResolveManyIn<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, TIn)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveManyIn<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, TIn input)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| TIn | input | The input to resolve multiple outputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveManyIn<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, params TIn[])
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveManyIn<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, params TIn[] list)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| TIn[] | list | A list of allowed input arguments |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveManyIn<TIn, TOut>(ITransformationTrace, TransformationRuleBase<TIn, TOut>, IEnumerable<TIn>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveManyIn<TIn, TOut>(this ITransformationTrace trace, TransformationRuleBase<TIn, TOut> rule, IEnumerable<TIn> list)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| TransformationRuleBase<TIn, TOut> | rule | The transformation rule the object was transformed with |
| System.Collections.Generic.IEnumerable<T><TIn> | list | A list of allowed input arguments |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The output that is returned by the transformation rule |
ResolveWhere<TOut>(ITransformationTrace, Type[], Predicate<object[]>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveWhere<TOut>(this ITransformationTrace trace, Type[] inputTypes, Predicate<object[]> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Type[] | inputTypes | The types of the input arguments that are expected to be matched |
| System.Predicate<T><object[]> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TOut | The output that is returned by the transformation rule |
ResolveWhere<TIn, TOut>(ITransformationTrace, Predicate<TIn>)
Trace the output of the computation that transformed any input that matches the filter into the desired type
Declaration
public static IEnumerable<TOut> ResolveWhere<TIn, TOut>(this ITransformationTrace trace, Predicate<TIn> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Predicate<T><TIn> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input type that is looked for |
| TOut | The desired output type |
ResolveWhere<TIn1, TIn2, TOut>(ITransformationTrace, Func<TIn1, TIn2, bool>)
Trace the output of the computation that transformed any input that matches the filter with the given transformation type
Declaration
public static IEnumerable<TOut> ResolveWhere<TIn1, TIn2, TOut>(this ITransformationTrace trace, Func<TIn1, TIn2, bool> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| System.Func<T1, T2, TResult><TIn1, TIn2, bool> | filter | The filter that should filter the inputs |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><TOut> | All outputs of computations with suitable input arguments or null, if there are none |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | |
| TIn2 | |
| TOut |
TraceInWhere(ITransformationTrace, GeneralTransformationRule, Predicate<object[]>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<ITraceEntry> TraceInWhere(this ITransformationTrace trace, GeneralTransformationRule rule, Predicate<object[]> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| GeneralTransformationRule | rule | The transformation rule |
| System.Predicate<T><object[]> | filter | The predicate of the inputs that are looked for |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><ITraceEntry> | A collection with all computations made under these circumstances |
TraceInWhere<TIn>(ITransformationTrace, GeneralTransformationRule<TIn>, Predicate<TIn>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<ITraceEntry> TraceInWhere<TIn>(this ITransformationTrace trace, GeneralTransformationRule<TIn> rule, Predicate<TIn> filter) where TIn : class
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| GeneralTransformationRule<TIn> | rule | The transformation rule |
| System.Predicate<T><TIn> | filter | The predicate of the inputs that are looked for |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><ITraceEntry> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TIn | The input argument type of the transformation |
TraceInWhere<TIn1, TIn2>(ITransformationTrace, GeneralTransformationRule<TIn1, TIn2>, Func<TIn1, TIn2, bool>)
Traces all computations with any inputs that math the given filters with the specified transformation rule
Declaration
public static IEnumerable<ITraceEntry> TraceInWhere<TIn1, TIn2>(this ITransformationTrace trace, GeneralTransformationRule<TIn1, TIn2> rule, Func<TIn1, TIn2, bool> filter)
Parameters
| Type | Name | Description |
|---|---|---|
| ITransformationTrace | trace | The trace component that is used as basis |
| GeneralTransformationRule<TIn1, TIn2> | rule | The transformation rule |
| System.Func<T1, T2, TResult><TIn1, TIn2, bool> | filter | The predicate of the inputs that are looked for |
Returns
| Type | Description |
|---|---|
| System.Collections.Generic.IEnumerable<T><ITraceEntry> | A collection with all computations made under these circumstances |
Type Parameters
| Name | Description |
|---|---|
| TIn1 | The first input argument type of the transformation |
| TIn2 | The first input argument type of the transformation |


Evaluating AI models in health
The ITU/WHO Focus Group on artificial intelligence for health (FG-AI4H) works in partnership with the World Health Organization (WHO) to establish a standardized assessment framework for the evaluation of AI-based methods for health, diagnosis, triage or treatment decisions. The group was established by ITU-T Study Group 16 at its meeting in Ljubljana, Slovenia, 9-20 July 2018.
System Architecture
Learn more about the FG-AI4H evaluation process
ML4H Auditing: From Paper to Practice.
Luis Oala, Jana Fehr, Luca Gilli, Pradeep Balachandran, Alixandro Werneck Leite, Saul Calderon-Ramirez, Danny Xie Li, Gabriel Nobis, Erick Alejandro Muñoz Alvarado, Giovanna Jaramillo-Gutierrez, Christian Matek, Arun Shroff, Ferath Kherif, Bruno Sanguinetti, Thomas WiegandProceedings of the Machine Learning for Health NeurIPS Workshop, PMLR 136:280-317, 2020
WHO and ITU establish Auditing process for artificial intelligence in health.
Thomas Wiegand, Ramesh Krishnamurthy, Monique Kuglitsch, Naomi Lee, Sameer Pujari, Marcel Salathé, Markus Wenzel, Shan XuThe Lancet, Volume 394, Issue 10192, 9 - 11, 2019


import numpy as np
import os, pickle
import re
from scipy import linalg
import scipy.ndimage as ndi
from six.moves import range
import os
import threading
import warnings
import multiprocessing.pool
from functools import partial
def _compute_zca_transform(imgs, filter_bias=0.1):
"""
Compute the zca whitening transform matrix.
"""
print("Computing ZCA transform matrix")
meanX = np.mean(imgs, 0)
covX = np.cov(imgs.T)
D, E = np.linalg.eigh(covX + filter_bias * np.eye(covX.shape[0], covX.shape[1]))
assert not np.isnan(D).any()
assert not np.isnan(E).any()
assert D.min() > 0
D = D ** -.5
W = np.dot(E, np.dot(np.diag(D), E.T))
return meanX, W
[docs]def zca_whiten(train, test, cache=None):
"""
Use train set statistics to apply the ZCA whitening transform to
both train and test sets.
"""
if cache and os.path.isfile(cache):
with open(cache, 'rb') as f:
(meanX, W) = pickle.load(f)
else:
meanX, W = _compute_zca_transform(train)
if cache:
print("Caching ZCA transform matrix")
with open(cache, 'wb') as f:
pickle.dump((meanX, W), f, 2)
print("Applying ZCA whitening transform")
train_w = np.dot(train - meanX, W)
test_w = np.dot(test - meanX, W)
return train_w, test_w
[docs]def global_contrast_normalize(X, scale=1., min_divisor=1e-8):
"""
Subtract mean and normalize by vector norm.
"""
X = X - X.mean(axis=1)[:, np.newaxis]
normalizers = np.sqrt((X ** 2).sum(axis=1)) / scale
normalizers[normalizers < min_divisor] = 1.
X /= normalizers[:, np.newaxis]
[docs]def random_rotation(x, rg, row_axis=1, col_axis=2, channel_axis=0,
fill_mode='nearest', cval=0.):
"""
Performs a random rotation of a Numpy image tensor.
Args:
x: Input tensor. Must be 3D.
rg: Rotation range, in degrees.
row_axis: Index of axis for rows in the input tensor.
col_axis: Index of axis for columns in the input tensor.
channel_axis: Index of axis for channels in the input tensor.
fill_mode: Points outside the boundaries of the input
are filled according to the given mode
(one of `{'constant', 'nearest', 'reflect', 'wrap'}`).
cval: Value used for points outside the boundaries
of the input if `mode='constant'`.
Returns:
Rotated Numpy image tensor.
"""
theta = np.pi / 180 * np.random.uniform(-rg, rg)
rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = transform_matrix_offset_center(rotation_matrix, h, w)
x = apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
[docs]def random_shift(x, wrg, hrg, row_axis=1, col_axis=2, channel_axis=0,
fill_mode='nearest', cval=0.):
"""
Performs a random spatial shift of a Numpy image tensor.
Args:
x: Input tensor. Must be 3D.
wrg: Width shift range, as a float fraction of the width.
hrg: Height shift range, as a float fraction of the height.
row_axis: Index of axis for rows in the input tensor.
col_axis: Index of axis for columns in the input tensor.
channel_axis: Index of axis for channels in the input tensor.
fill_mode: Points outside the boundaries of the input
are filled according to the given mode
(one of `{'constant', 'nearest', 'reflect', 'wrap'}`).
cval: Value used for points outside the boundaries
of the input if `mode='constant'`.
Returns:
Shifted Numpy image tensor.
"""
h, w = x.shape[row_axis], x.shape[col_axis]
tx = np.random.uniform(-hrg, hrg) * h
ty = np.random.uniform(-wrg, wrg) * w
translation_matrix = np.array([[1, 0, tx],
[0, 1, ty],
[0, 0, 1]])
transform_matrix = translation_matrix # no need to do offset
x = apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
[docs]def random_shear(x, intensity, row_axis=1, col_axis=2, channel_axis=0,
fill_mode='nearest', cval=0.):
"""
Performs a random spatial shear of a Numpy image tensor.
Args:
x: Input tensor. Must be 3D.
intensity: Transformation intensity.
row_axis: Index of axis for rows in the input tensor.
col_axis: Index of axis for columns in the input tensor.
channel_axis: Index of axis for channels in the input tensor.
fill_mode: Points outside the boundaries of the input
are filled according to the given mode
(one of `{'constant', 'nearest', 'reflect', 'wrap'}`).
cval: Value used for points outside the boundaries
of the input if `mode='constant'`.
Returns:
Sheared Numpy image tensor.
"""
shear = np.random.uniform(-intensity, intensity)
shear_matrix = np.array([[1, -np.sin(shear), 0],
[0, np.cos(shear), 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = transform_matrix_offset_center(shear_matrix, h, w)
x = apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
[docs]def random_zoom(x, zoom_range, row_axis=1, col_axis=2, channel_axis=0,
fill_mode='nearest', cval=0.):
"""
Performs a random spatial zoom of a Numpy image tensor.
Args:
x: Input tensor. Must be 3D.
zoom_range: Tuple of floats; zoom range for width and height.
row_axis: Index of axis for rows in the input tensor.
col_axis: Index of axis for columns in the input tensor.
channel_axis: Index of axis for channels in the input tensor.
fill_mode: Points outside the boundaries of the input
are filled according to the given mode
(one of `{'constant', 'nearest', 'reflect', 'wrap'}`).
cval: Value used for points outside the boundaries
of the input if `mode='constant'`.
Returns:
Zoomed Numpy image tensor.
Raises:
ValueError: if `zoom_range` isn't a tuple.
"""
if len(zoom_range) != 2:
raise ValueError('`zoom_range` should be a tuple or list of two floats. '
'Received arg: ', zoom_range)
if zoom_range[0] == 1 and zoom_range[1] == 1:
zx, zy = 1, 1
else:
zx, zy = np.random.uniform(zoom_range[0], zoom_range[1], 2)
zoom_matrix = np.array([[zx, 0, 0],
[0, zy, 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = transform_matrix_offset_center(zoom_matrix, h, w)
x = apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
def random_channel_shift(x, intensity, channel_axis=0):
x = np.rollaxis(x, channel_axis, 0)
min_x, max_x = np.min(x), np.max(x)
channel_images = [np.clip(x_channel + np.random.uniform(-intensity, intensity), min_x, max_x)
for x_channel in x]
x = np.stack(channel_images, axis=0)
x = np.rollaxis(x, 0, channel_axis + 1)
return x
[docs]def random_channel_shift(x, intensity, channel_axis=0):
x = np.rollaxis(x, channel_axis, 0)
min_x, max_x = np.min(x), np.max(x)
channel_images = [np.clip(x_channel + np.random.uniform(-intensity, intensity), min_x, max_x)
for x_channel in x]
x = np.stack(channel_images, axis=0)
x = np.rollaxis(x, 0, channel_axis + 1)
return x


Users
You will need users to get more work done on your site, the CMS tool allows you to add users with custom logins and roles to what they can do.
Fill out the user registration form and press the submit button to create a user
Similar to managing content which we went through in the previous page to edit, view or delete users navigate to the users tab on the side menu and click "View Users". You will be presented with a list view of all the users registered in the CMS.
Roles
Roles hold a list of permissions which you assign to each user so they are able do what they
what they need to do. To create a new Role navigate to the "User" tab on the side menu and select
the sub menu item "Add Role". Similar to managing content which we went through in the previous page
to view, edit and delete roles Navigate to the "User" tab on the sire menu and
select View Roles.
Permisions
Here is the list of permissions you will be able to give to a single User
Supported Get Requests
"getUser", "getUserFromId", "getAllUsers", "getAllRoles", "getRole", "getBlog",
"getAllBlogs", "getPage", "getAllPages", "getPresignedPostImage",
"getSiteSettings", "getNavItems"
Supported Put Requests
"putUser", "putRole", "putBlog", "editBlog", "putPage", "putNavItems",
"putSiteSettings"
Supported Delete Requests
"deleteUser", "deleteRole", "deleteBlog", "deletePage"


|
Frequently Asked Questions -- The Questions
Overview
Frequently Asked Questions -- The Answers Overview
Catalyst is a group of tutors who operate a drop-in math homework help program at Hosmer Community Library. Typically, we have 1 or 2 students working with a single tutor. Catalyst math tutors are knowledgeable in math topics commonly taught at the middle school, junior high, and senior high school levels. Since our inception, we have helped students with…
While the Catalyst tutors have some basic materials (e.g. pencils, paper, rulers, non-graphing calculators) at their sessions, students should also come prepared with the following items to help the tutors determine the best way to assist them:
|


[TITLE 25A. GENERAL BUSINESS PROVISIONS]
Chapter
474 Business Action Center
[CHAPTER 474]
BUSINESS ACTION CENTER
Section
474-1 Definitions
474-2 Business action center established; staff
474-3 General functions; powers and duties
474-4 Cooperation from state agencies
474-5 Comprehensive permit and license information file
474-6 Immunity from liability
474-7 Compilation of statistical data; annual report
Note
Transfer of functions, duties, etc. L 2005, c 62, §§4 to 8.


BackTrack helps you discover when, why, and how your posture changes throughout the day.
Target problem areas with real-time feedback about back, neck, and shoulder position. BackTrack also calibrates to common work activities, such as standing and sitting.
Instead of vibration, BackTrack's wristband provides a gentle squeeze to remind you when to sit up.
Tie your shoes with dignity, not notifications. Teach BackTrack which types of movements to ignore.
BackTrack works with your existing wearables. Get information about your posture without ever opening an app.
A promotional video demonstration of BackTrack.


{% extends "base.html" %} {% block content %}
Oops, look like we broke something. We received a notification and will fix it as soon as possible. In the meantime, you can go back to our Homepage.


INSTALL-INFO(1) INSTALL-INFO(1) NAME install-info - wrapper around GNU install-info SYNOPSIS install-info [options] DESCRIPTION This manual page documents briefly the install-info command. This manual page was written for the Debian GNU/Linux distribution because the origi‐ nal script was designed for Debian packaging system. install-info is a wrapper around GNU install-info. If it is called from a normal shell or script it acts like GNU install-info by forwarding all options to ginstall-info. If it is called from a maintainer script it gives a warning to rebuild packages and does nothing, since info file installation is now done via triggers. OPTIONS Same as with GNU install-info, see ginstall-info(1). AUTHOR This manual page was written by Norbert Preining<EMAIL_ADDRESS>for the Debian GNU/Linux system (but may be used by others). INSTALL-INFO(1)


Synonyms for tidbit: goody, delicacy, snack, treat, tweet
partly from thesaurus.com.


JavaScript is disabled on your browser.
Skip navigation links
Overview
Package
Class
Tree
Deprecated
Index
Help
Prev Package
Next Package
Frames
No Frames
All Classes
Package it.polimi.deib.newdem.adrenaline.controller.effects.selection
Interface Summary
Interface
Description
PlayerSelector
The player selector is a logical predicate that can discriminate players by different criteria.
TileSelector
A tile selector defines a predicate that discriminates tiles by different criteria.
Class Summary
Class
Description
AnyDirectionalTileSelector
AnyPlayerSelector
AnyTileSelector
BlackListFilterPlayerSelector
DirectionalPlayerSelector
IntersectPlayerSelector
IntersectTileSelector
NearPlayerSelector
NearTileSelector
NegatedPlayerSelector
NegatedTileSelector
SameRoomTileSelector
SameTilePlayerSelector
TestAnyDirectionalTileSelector
TestDirectionalPlayerSelector
TestIntersectPlayerSelector
TestIntersectTileSelector
TestNearPlayerSelector
TestNearTileSelector
TestSameRoomTileSelector
TestUnionPlayerSelector
TestUnionTileSelector
TestVisiblePlayerSelector
TestVisibleTileSelector
UnionPlayerSelector
UnionTileSelector
VisiblePlayerSelector
VisibleTileSelector
WhileListFilterPlayerSelector
Skip navigation links
Overview
Package
Class
Tree
Deprecated
Index
Help
Prev Package
Next Package
Frames
No Frames
All Classes


Decodable
Simple and strict, yet powerful object mapping made possible by Swift 2’s error handling. Greatly inspired by Argo, but without a bizillion functional operators.
struct Repository {
let name: String
let description: String
let stargazersCount: Int
let language: String?
let sometimesMissingKey: String?
let owner: User // Struct conforming to Decodable
let defaultBranch: Branch // Struct NOT conforming to Decodable
var fullName: String { return "\(owner.login)/\(name)" }
}
extension Repository: Decodable {
static func decode(j: Any) throws -> Repository {
return try Repository(
name: j => "nested" => "name",
description: j => "description",
stargazersCount: j => "stargazers_count",
language: j => "language",
sometimesMissingKey: j =>? "sometimesMissingKey",
owner: j => "owner",
defaultBranch: Branch(name: j => "default_branch")
)
}
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
let repo = try [Repository].decode(json)
} catch {
print(error)
}
How does it work?
A protocol
public protocol Decodable {
static func decode(json: Any) throws -> Self
}
A parse-function
public func parse<T>(json: Any, path: [String], decode: (Any throws -> T)) throws -> T
And shameless operator-overloading
The too-many generated overloads, all calling the parse
-function, can be found in Overloads.swift. Return types include T?
, [T?]
, [T?]?
, Any
and [String: T]?
. When conditional protocol conformance is supported in Swift this won’t be necessary, and automatic decoding of infinitely nested generic types (like [[[[[[[[[A???]]: B]]]?]]?]]
) would work.
An overload may look like this:
public func => <T: Decodable>(json: Any, keyPath: KeyPath) throws -> T
KeyPaths
Keypaths can be created from string and array literals as well as with explicit initializers. They can also be joined using the operators =>
and =>?
. =>?
is another operator that indicates that nil
should be returned if the key to the right is missing.
- When composing
=>
and=>?
operators in the same keypath, the strictness of=>
is still honoured. - Optional key paths (
=>?
) require an optional return type
let a: KeyPath = "a"
let b: KeyPath = ["a", "b"]
let c: KeyPath = "a" => "b" => "c"
let string: String? = json =>? "key1" => "key2" => "key3"`
^^^^ allowed to be missing
Errors
Errors will be caught and rethrown in the decoding process to backpropagate metadata, like the JSON object that failed decoding, the key path to it, and the root JSON object.
From DecodingError.swift:
public enum DecodingError: ErrorProtocol, Equatable {
/// Thrown when optional casting from `Any` fails.
///
/// This can happen both when trying to access a key on a object
/// that isn't a `NSDictionary`, and failing to cast a `Castable`
/// primitive.
case typeMismatch(expected: Any.Type, actual: Any.Type, Metadata)
/// Thrown when a given, required, key was not found in a dictionary.
case missingKey(String, Metadata)
/// Thrown from the `RawRepresentable` extension when
/// `init(rawValue:)` returned `nil`.
case rawRepresentableInitializationError(rawValue: Any, Metadata)
/// When an error is thrown that isn't `DecodingError`, it
/// will be wrapped in `DecodingError.other` in order to also provide
/// metadata about where the error was thrown.
case other(ErrorProtocol, Metadata)
}
let dict: NSDictionary = ["object": ["repo": ["owner": ["id" : 1, "login": "anviking"]]]]
do {
let username: String = try dict => "object" => "repo" => "owner" => "name"
} catch let error {
print(error)
}
//
// MissingKeyError at object.repo.owner: name in {
// id = 1;
// login = anviking;
// }
Handling Errors
Expressions like j => "key"
will throw directly, and catch
-statements can be used to create the most complex error handling behaviours. This also means that try?
can be used to return nil if anything goes wrong instead of throwing.
For convenience there is an operator, =>?
, that only returns nil on missing keys, for APIs that indicate null
in that manner, and to aid working with different response formats.
| Overload | Null Behaviour | Missing Key Behavior | Type Mismatch Behaviour | Errors in subjects |
|---|---|---|---|---|
=> -> T |
throws | throws | throws | uncaught (throws) |
=> -> T? |
nil | throws | throws | uncaught (throws) |
=>? -> T? |
nil | nil | throws | uncaught (throws) |
try? => -> T |
nil | nil | nil | caught (nil) |
Customization
Int
, Double
,String
, Bool
, Date
(ISO8601), NSArray
, and NSDictionary
types that conform to DynamicDecodable
with the following declaration:
public protocol DynamicDecodable {
associatedtype DecodedType
static var decoder: (Any) throws -> DecodedType {get set}
}
This allows Decodable to implement default decoding closures while allowing you to override them as needed.
// Lets extend Bool.decoder so that it accepts certain strings:
Bool.decoder = { json in
switch json {
case let str as String where str == "true":
return true
case let str as String where str == "false":
return false
default:
return try cast(json)
}
}
Note that when extending new types to conform to Decodable
there is really no point in conforming to DynamicDecodable
since you already control the implementation. Also note that the decoder
properties are intended as set once
. If you need different behaviour on different occasions, please create custom decode functions.
The default Date.decoder
uses a ISO8601 date formatter. If you don’t want to create your own decode closure there’s a helper:
Date.decoder = Date.decoder(using: formatter)
When Decodable
isn’t enough
Don’t be afraid of not conforming to Decodable
.
let array = try NSArray.decode(json => "list").map {
try Contribution(json: $0, repository: repo)
}
Tips
- You can use
Decodable
with classes. Just make sure to either call arequired
initializer on self (e.gself.init
) and returnSelf
, or make your classfinal
. ( This might be a problem though) - The
Decodable
-protocol and the=>
-operator should in no way make you committed to use them everywhere.
Compatibility
| Swift version | Compatible tag or branch |
|---|---|
| Swift 5.0 | 0.7.0 |
| Swift 4.0 | 0.6.0 |
| Swift 3.0 | v0.5 |
| Swift 2.3 | v0.4.4 |
| Swift 2.2 | v0.4.3 |
Note on Swift 4.0 usage
Due to collisions with the standard library you will have to import ambiguous symbols specifically, in addition to Decodable
as a whole.
This means you likely want the following
import Decodable
import protocol Decodable.Decodable
and you can import other symbols, e.g KeyPath
, DecodingError
, in a similar fashion (using import struct
and import enum
)


ABOUT DESIGN FEST
Register in the eventLorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi, vel omnis repellendus mollitia, explicabo, maiores quisquam numquam quia reiciendis sit, accusantium atque ex animi perspiciatis ab odit earum assumenda aliquid.
Dolor sit amet, consectetur adipisicing elit. Commodi, vel omnis repellendus mollitia, explicabo, maiores quisquam numquam quia reiciendis sit, accusantium atque ex animi perspiciatis ab odit earum assumenda aliquid.
00
Event DAYS
00 +
CONFRENCES
00 +
WORKSHOPS
SPEAKERS
View all SpeakersFirst LastName
Web Devaloper @Micro Club
First LastName
Web Devaloper @Micro Club
First LastName
Web Devaloper @Micro Club
ABOUT DESIGN FEST
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi, vel omnis repellendus mollitia, explicabo, maiores quisquam numquam quia reiciendis sit, accusantium atque ex animi perspiciatis ab odit earum assumenda aliquid.
Dolor sit amet, consectetur adipisicing elit. Commodi, vel omnis repellendus mollitia, explicabo, maiores quisquam numquam quia reiciendis sit, accusantium atque ex animi perspiciatis ab odit earum assumenda aliquid.
Schedule
Registration And Breakfast
- Name LastName
8:00 am
Registration And Breakfast
- Name LastName
10:00 am
Registration And Breakfast
- Name LastName
1:00 pm
Registration And Breakfast
- Name LastName
3:00 pm
Registration And Breakfast
- Name LastName
8:00 am
Registration And Breakfast
- Name LastName
10:00 am
Registration And Breakfast
- Name LastName
1:00 pm
Registration And Breakfast
- Name LastName
3:00 pm
Registration And Breakfast
- Name LastName
8:00 am
Registration And Breakfast
- Name LastName
10:00 am
Registration And Breakfast
- Name LastName
1:00 pm
Registration And Breakfast
- Name LastName
3:00 pm
Workshops
View all WorkshopsAdobe Illustrator
This Training is made by ... for ... and some other details bla bla bla bla bla bla read more...
Adobe Illustrator
This Training is made by ... for ... and some other details bla bla bla bla bla bla read more...
Adobe Illustrator
This Training is made by ... for ... and some other details bla bla bla bla bla bla read more...
Adobe Illustrator
This Training is made by ... for ... and some other details bla bla bla bla bla bla read more...


Blocks, Procs, and Lambdas
Blocks
When learning Ruby, a common refrain is that "everything is an object." As it turns out this is not entirely true. One of the rare exceptions is our friend, the block. A block is just a bit of code that can be executed. The reason blocks aren't considered objects is because they can't be saved to a variable, and they don't have all the functionality in an object's repertoire.
As for syntax, a block is denoted by curly braces ({}
) or by do
...end
. Some common methods that are followed by a block are #each
, #times
, and #collect
, but there are a ton of others.
Procs
Let's say you have a block of code that you intend to use several times in a program. Wouldn't it be cool if you could save it to a variable and just use that variable instead of having to write out that bit of code every time you wanted to execute it? Well, that's what procs are for.
Creating procs is very similar to creating other objects. All you have to do is call Proc.new
and pass in a block of code. So for example,
double = Proc.new { |i| i * 2 }
[1, 2, 3].map(&double) # => [2, 4, 6]
(the "&" in front of the Proc variable name just converts the proc into a block since that's what #map normally takes)
There's another useful way to call a Proc, and that's with the #call method. Check it,
jamaican = Proc.new { puts "whatta gwan" }
jamaican.call # => "whatta gwan"
Lambdas
With the exception of a couple of small details, lambdas and procs are essentially the same thing. There's a slight difference in how you create new procs and lambdas, as seen here:
jamaican = Proc.new { puts "whatta gwan" }
jamaican = lambda { puts "whatta gwan" }
Other than that, lambdas are aware of the number of arguments that gets passed to it while procs are not. Lambdas will throw an error if they get the wrong number of arguments; procs make do by either ignoring extra arguments or adding nil values if there aren't enough.
And finally, when a lambda returns whatever value it's supposed to return, it passes control back to the method that called it. So if the calling method then returns another value (after the lambda), it will do so unimpeded. Procs on the other hand will return and not pass control back to the calling method. So once the proc returns its value, the calling method does not return anything else that follows the proc, even if it's written in such a way that suggests that a value should be returned.