I want to avoid creating a switch case and instead use an enum but when writing the following code, I get a compile error saying unexpected token public:
public enum Status {
INACTIVE {
public void doSomething() {
//do something
}
},
ACTIVE {
public void doSomething() {
//do something else
}
},
UNKNOWN {
public void doSomething() {
//do something totally different
}
};
public abstract void doSomething()
}
Basically what I want to achieve is something similar to this:
public enum Status {
ACTIVE,
INACTIVE,
UNKNOWN;
}
switch (getState()) {
case INACTIVE:
//do something
break;
case ACTIVE:
//do something else
break;
case UNKNOWN:
//do something totally different
break;
}
Is this allowed in Gosu? How should I go about achieving such a behavior?
You have miss-understood the concept of Enum. First of all, enum is inherited from java.lang.Enum. It's not allowed to implement inner classes to Enum constants. You have to consider ACTIVE,INACTIVE and UNKNOWN (Enum constants) as objects of class type Status.
Proof:
Status.ACTIVE.getClass() == class Status
Status.ACTIVE instanceof Status == true
Status.ACTIVE instanceof java.lang.Enum == true
If you want to avoid the switch statement in your main code, you can move the switch into the implementation of enum as follows; (coded in Gosu)
enum Status {
ACTIVE,INACTIVE,UNKNOWN;
public function doSomething(){
switch (this) {
case INACTIVE:
//do something
break;
case ACTIVE:
//do something
break;
case UNKNOWN:
//do something
break;
}
}
}
Now you have the capability to call the doSomething() method from the enum constants in your main code
Example:
var a=Status.ACTIVE
var b=Status.INACTIVE
var c=Status.UNKNOWN
a.doSomething()
b.doSomething()
c.doSomething()
As you can read in
Gosu grammar or below function is not allowed inside enum consts, even brackets {} after consts are not allowed.
What is allowed in enum body:
enumBody = "{" [enumConstants] classMembers "}" .
enumConstants = enumConstant {"," enumConstant} [","] [";"] .
enumConstant = {annotation} id optionalArguments .
So basically in GOSU enum contains consts and rest normally as in any other class.
Related
I'm trying to implement a chain of function calls that could be expensive on their own, and I would like to only call the subsequent functions if the result of the previous satisfied the condition(s). For instance, I have these "models":
data class In(val a: Int, val c: String, val f: String, val t: String)
data class Out(val passed: Boolean, val code: String?)
...then this is the logic (never mind the variables/method names):
class Filter : SomeFilter {
override fun filter(input: In): Out {
return Stream.of(chML(input), chC(input), chA(input))
.filter { !it.passed }
.findFirst()
.orElseGet { Out(true, "SUCCESS") }
}
private fun chC(input: In): Out {
if (input.c !== "ADA") {
return Out(false, "INVALID_C")
}
return Out(true, "SUCCESS")
}
private fun chA(input: In): Out {
if (input.a >= 100) {
return Out(false, "INVALID_A")
}
return Out(true, "SUCCESS")
}
private fun chML(input: In): Out {
if (context.contains(input.f)) {
// context.add(input.to)
return Out(false, "INVALID_ML")
}
return Out(true, "SUCCESS")
}
}
The problem with these functions is that they should be expensive, so if the output from any of those is Out.passed === false, then I wouldn't like to call the next one because it could be interpreted as a terminal operation at that point.
Is there a way to implement this in such way without going the if/else-if route? The approach with streams is cleaner, but it does execute all the functions, regardless.
You can use sequence and yield
fun filter(input: In): Out {
return sequence {
yield(chML(input))
yield(chC(input))
yield(chA(input))
}
.firstOrNull { !it.passed }
?: Out(true, "SUCCESS")
}
You can use function references and invoke them in a map operation. Kotlin Sequences short-circuit based on any filters in the chain, including firstOrNull.
override fun filter(input: In): Out {
return sequenceOf(::chML, ::chC, ::chA)
.map { it(input) }
.firstOrNull { !it.passed }
?: Out(true, "SUCCESS")
}
By the way, I advise against using === or !== with Strings. That is checking reference equality which is very hard to use reliably unless all your source strings are private to this class so you can carefully make sure you know where/when they were instantiated and whether they were string literals. You should probably use != instead.
I have a kotlinjs app. I handle a particular event (dropping of data onto a component) like this:
onEvent {
drop = { event ->
GlobalScope.async {
//...
dropTask(y, data)
}
}
}
// ...
// this function has to be a suspend function because model's is
private suspend fun dropTask(y: Int, taskId: TaskId) {
// ... prepare data
model.insertBefore(taskId!!, insertBefore?.id)
}
// ... Model's function is defined like this:
suspend fun insertBefore(taskToInsert: TaskId, taskBefore: TaskId?) {
val (src, _) = memory.find(taskToInsert)
// ... and finally, the find function is:
fun find(taskId: TaskId): Pair<Task?, Int> {
// ...
return if (task != null) {
// ...
} else {
throw Exception("Couldn't find task with id $taskId!!")
}
}
The issue is that the Exception gets thrown, but isn't reported anywhere.
I have tried:
a) Installing a CoroutineExceptionHandler into the GlobalScope.async (i.e.:
val handler = CoroutineExceptionHandler { _, e ->
console.log("Caught exception: $e")
}
GlobalScope.async(handler) {
...but this never gets called. This would be relatively clean if I could make it work. It would be even nicer if this was default behavior for kotlinjs, so that exceptions weren't accidentally unreported.
b) Calling await:
drop = { event ->
GlobalScope.launch {
GlobalScope.async() {
// ...
dropTask(y, data)
}.await()
}
}
This does result in the exception being logged to the console, but it's so ugly. It's not possible to call .await() outside of a suspend function or coroutine, so for this particular event handler I have to wrap the async call in a launch. I must be doing something wrong. Anybody have a better pattern that I should be using?
Given the following enum defined in an external api.
public enum Status {
COMPLETE,
RUNNING,
WAITING
}
I would like a way to add a int flag to each enum value. I know that I can extend the enum:
fun Status.flag(): Int {
when(this) {
RUNNING -> return 1;
WAITING -> return 2;
else -> return 0;
}
}
However I would like to define those int flag values as constants. Maybe a companion object, but I don't think I can extend an existing enum and add a companion object.
Any ideas?
Unless you are using a field that already exists in the original enum (like ordinal), you won't be able to do what you're asking without wrapping the external enum in your own enum.
Sure you could use ordinal, but a newer version of the external API may change the order of the items in the enum, so I wouldn't recommend it. But, if you REALLY want to, you could do something like this (again, this is NOT recommended):
val Status.flag: Int
get() = this.ordinal
But I'd definitely recommend wrapping it. That way you guarantee that the flag integers you define won't change.
enum class MyStatus(val status: Status, val flag: Int) {
COMPLETE(Status.COMPLETE, 0),
RUNNING(Status.RUNNING, 1),
WAITING(Status.WAITING, 2);
companion object {
private val STATUS_TO_MYSTATUS = values().associateBy { it.status }
fun fromStatus(status: Status): MyStatus {
return STATUS_TO_MYSTATUS[status] ?: throw Exception("No MyStatus found for status ${status.name}")
}
}
}
You can then convert Status to MyStatus by using MyStatus.fromStatus(...). Or you can add an extension function to Status to easily convert to MyStatus.
fun Status.toMyStatus() = MyStatus.fromStatus(this)
You can add extension properties/methods to the companion object of enum/class/etc. if one exists:
val Status.Companion.COMPLETE_INT = 0
val Status.Companion.RUNNING_INT = 1
but indeed you can't currently "create" the companion object if it doesn't. So just put the constants into your own non-companion object:
object StatusFlags {
const val COMPLETE_INT = 0
const val RUNNING_INT = 1
const val WAITING_INT = 2
}
fun Status.flag(): Int {
when(this) {
RUNNING -> return StatusFlags.RUNNING_INT
...
}
}
Looking at the example here at Message Controller for Pizza Example, if I want to populate Size or Kind based on some user input and make a call to the database, how would I do that?
So far as I know, there is not an easy way to populate the Enum at runtime.
It looks like this hasn't been implemented yet. I took a look inside https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Library/FormFlow/FormBuilder.cs and found this:
internal static void TypePaths(Type type, string path, List<string> paths)
{
if (type.IsClass)
{
if (type == typeof(string))
{
paths.Add(path);
}
else if (type.IsIEnumerable())
{
var elt = type.GetGenericElementType();
if (elt.IsEnum)
{
paths.Add(path);
}
else
{
// TODO: What to do about enumerations of things other than enums?
}
}
else
{
FieldPaths(type, path, paths);
}
}
else if (type.IsEnum)
{
paths.Add(path);
}
else if (type == typeof(bool))
{
paths.Add(path);
}
else if (type.IsIntegral())
{
paths.Add(path);
}
else if (type.IsDouble())
{
paths.Add(path);
}
else if (type.IsNullable() && type.IsValueType)
{
paths.Add(path);
}
else if (type == typeof(DateTime))
{
paths.Add(path);
}
}
Notice the TODO about enumerations other than enums.
Outside of the FormBuilder we can use PromptDialog.Choice which takes an IEnumerable<> of your options.
It is possible to chain dialogs together, so you may have to split your FormDialog into two with the PromptDialog in-between.
Alternatively take a fork of BotBuilder and implement the TODO!
I want to specify a type constraint that the type should be a raw value enum:
enum SomeEnum: Int {
case One, Two, Three
}
class SomeProtocol<E: enum<Int>> { // <- won't compile
func doSomething(e: E) {
compute(e.toRaw())
}
}
How can I do it in Swift? (I used the F# syntax for example)
enum SomeEnum: Int {
case One, Two, Three
}
class SomeClass<E: RawRepresentable where E.RawValue == Int>{
func doSomething(e: E) {
print(e.rawValue)
}
}
class SomeEnumClass : SomeClass<SomeEnum> {
}
or directly
class SomeOtherClass{
func doSomething<E: RawRepresentable where E.RawValue == Int>(e: E) {
print(e.rawValue)
}
}
UPDATE for swift3:
enum SomeEnum: Int {
case One, Two, Three
}
class SomeClass<E: RawRepresentable> where E.RawValue == Int {
func doSomething(e: E) {
print(e.rawValue)
}
}
class SomeEnumClass : SomeClass<SomeEnum> {
}
resp.
class SomeOtherClass{
func doSomething<E: RawRepresentable>(e: E) where E.RawValue == Int {
print(e.rawValue)
}
}
While you can place enums into a generic type without contraints (<T>), it's not possible to create constraints for all enums or all structs. All the constraints are based on interfaces (subclassing, protocols). Unfortunately, there is nothing in common between two random structs or two random enums.
Structs and enums can't inherit from other structs/enums so the only constraints for enums must be based on protocols.
protocol EnumProtocol {
func method()
}
enum TestEnum : Int, EnumProtocol {
case A
case B
func method() {
}
}
enum TestEnum2 : Int, EnumProtocol {
case C
func method() {
}
}
class EnumGeneric <T : EnumProtocol> {
func method(a: T) {
a.method()
}
}
let test = EnumGeneric<TestEnum>()
test.method(TestEnum.A)
Also note that all enums "inheriting" from a primitive type like Int conform to RawRepresentable, so you could
class EnumGeneric <T : RawRepresentable> {
func method(a: T) {
println("\(a.toRaw())");
}
}
but that won't work for enums declared as enum TestEnum {
AFAIK, Swift does not support type constraint to be specified with enums.
Cited from Swift Manual
Type Constraint Syntax
You write type constraints by placing a single class or protocol
constraint after a type parameter’s name, separated by a colon, as
part of the type parameter list. The basic syntax for type constraints
on a generic function is shown below (although the syntax is the same
for generic types):
Strictly limited to a class or protocol unless there's some hidden features which is not mentioned in manual. As far as I tested, struct or enum are all prohibited by the compiler.
enum Test1 : Int
{
case AAA = 0
}
func test1f<T:Test1>(a: Test1) {} // error: Inheritance from non-protocol, non-class type 'Test1'
struct Test2
{
var aaa:Int = 0
}
func test2f<T:Test2>(a: Test2) {} // error: Inheritance from non-protocol, non-class type 'Test1'
class Test3
{
}
func test3f<T:Test3>(a: Test3) {} // OK