I am struggling to do a comparison of objects without the compiler complaining. I know how to do this in C#, but not Fantom (new to Fantom); please help.
class Boomtown {
// Objects entered into foo are classes which inherit Foo class
Foo?[] foo := Foo?[,].fill(8,null)
internal Future? doSomething( Foo something ) {
// Does foo have items?
haveFoo := foo.findAll | v | { v != null }
if( haveFoo.size > 0 ) {
// This where I start to get lost
foundDiff := haveFoo.each | v | {
if( v isnot something ) { // Compiler doesn't like this: Unknown type 'something'
return true
}
}
...
}
}
Thanks in advance for any help.
SlimerDudeWed 22 Jul 2020
Hi Dan B,
You didn't say what the compiler errors were - but I found a few - a couple being:
it's Foo?[,].fill(null, 8) - not Foo?[,].fill(8,null)
And something would need to be a defined class like Foo.
For what you want, I think you'll need to use List.all() or List.any(), like this:
class Boomtown {
// Objects entered into foo are classes which inherit Foo class
Foo?[] foo := Foo?[,].fill(null, 8)
internal Obj? doSomething( Foo something ) {
// Does foo have items?
haveFoo := foo.all |v| { v == null || v is Foo }
echo(haveFoo)
return null
}
}
class Foo { }
Dan BWed 22 Jul 2020
I just tried the following; which results in the same compiler error.
I don't think I have asked the question correctly or provided the correct background.
We have the following classes
MicroTask: very basic just holds an integer 0 to 7
AmAcWrTask: Inherits MicroTask (i.e. class AmAcWrTasl : MicroTask)
AutoConfigTask: Inherits AmAcWrTask
AutoMatchTask: Inherits AmAcWrTask
WireResistanceTask: Inherits AmAcWrTask
SyncConfigTask: Inherits MicroTask
Then in another class
private MicroTask?[] activeMicroTasks := MicroTask?[,].fill(null, 8)
private MicroTask?[] delayedMicroTasks := MicroTask?[,].fill(null, 8)
// Run a task for a particular micro
internal Future? runMicroTask( MicroTask task, Bool checked := true, Bool autoStatus := true ) {
// Input arg "task" can be one of: AutoConfigTask, AutoMatchTask, SyncConfigTask, or WireResistanceTask
// Class variable "activeMicroTasks" will contain the "task" at the correct index later in this function.
// I am trying to detect when runMicroTask is called with a different task type than what task type(s)
// is contained in activeMicroTasks.
// If it is different the incoming task is placed in delayedMicroTasks, to be run later
...
}
The type checking in the background function works as expected.
// Background function, runs periodically
Void backgrouFunc() {
...
else {
// SAGE-1907: Maestro fails to send POST to start WR
haveActive := activeMicroTasks.findAll | v | { v != null }
haveDelayed := delayedMicroTasks.findAll | v | { v != null }
// Do we have any task that were delayed?
if( ( haveActive.size == 0 ) && ( haveDelayed.size > 0 ) ) {
Device.log.info( "[BG Thread] delayedMicroTasks: $delayedMicroTasks ")
delayedMicroTasks.each | MicroTask? m, Int j | {
// Mark it as null so we don't repeat it
delayedMicroTasks[ j ] = null
if( m is SyncMicroConfigTask ){
syncConfigMicros.add( j )
}
else if( m is AutoMatchTask ) {
autoMatchMicros.add( j )
}
else if( m is AutoConfigTask ) {
autoConfigMicros.add( j )
}
else if( m is WireResistanceTask ) {
Device.log.info( "[BG Thread] Adding delayed WR task for micro $j" )
wireResistanceMicros.add( j )
}
}
}
}
}
Dan BWed 22 Jul 2020
My solution. Was hoping for something a little more elegant
haveSync := activeMicroTasks.any | v | { v != null && v is SyncMicroConfigTask }
haveAC := activeMicroTasks.any | v | { v != null && v is AutoConfigTask }
haveAM := activeMicroTasks.any | v | { v != null && v is AutoMatchTask }
haveWR := activeMicroTasks.any | v | { v != null && v is WireResistanceTask }
// There is active tasks. Now check the type of active
// versus the requested (passed in) task
if( ( ( haveSync ) && ( task isnot SyncMicroConfigTask ) ) ||
( ( haveAC ) && ( task isnot AutoConfigTask ) ) ||
( ( haveAM ) && ( task isnot AutoMatchTask ) ) ||
( ( haveWR ) && ( task isnot WireResistanceTask ) ) )
{
canRun = false
}
else
{
canRun = true
}
SlimerDudeWed 22 Jul 2020
Was hoping for something a little more elegant
I dunno, that logic looks kinda complicated to me...
I mean, if you wanted to reduce the code, you could loop over the types:
But then I'd argue you loose a lot of readability as to what the code actually does... time to break out the unit tests!
Dan BWed 22 Jul 2020
Yes, I like the readability of my solution
Dan BFri 24 Jul 2020
Actually Jeremy provided a clean and readable solution.
haveActive := activeMicroTasks.findAll | v | { v != null }
canRun := haveActive.any{ it.typeof.fits( task.typeof ) }
brianFri 24 Jul 2020
In the upcoming release there is also a findNotNull method. But one method that will filter out nulls and find a specific type is the sys::List.findType method:
Dan B Wed 22 Jul 2020
I am struggling to do a comparison of objects without the compiler complaining. I know how to do this in C#, but not Fantom (new to Fantom); please help.
class Boomtown { // Objects entered into foo are classes which inherit Foo class Foo?[] foo := Foo?[,].fill(8,null) internal Future? doSomething( Foo something ) { // Does foo have items? haveFoo := foo.findAll | v | { v != null } if( haveFoo.size > 0 ) { // This where I start to get lost foundDiff := haveFoo.each | v | { if( v isnot something ) { // Compiler doesn't like this: Unknown type 'something' return true } } ... } }Thanks in advance for any help.
SlimerDude Wed 22 Jul 2020
Hi
Dan B,You didn't say what the compiler errors were - but I found a few - a couple being:
Foo?[,].fill(null, 8)- notFoo?[,].fill(8,null)foundDiff := haveFoo.each-each()doesn't return anythingAnd
somethingwould need to be a defined class likeFoo.For what you want, I think you'll need to use List.all() or List.any(), like this:
class Boomtown { // Objects entered into foo are classes which inherit Foo class Foo?[] foo := Foo?[,].fill(null, 8) internal Obj? doSomething( Foo something ) { // Does foo have items? haveFoo := foo.all |v| { v == null || v is Foo } echo(haveFoo) return null } } class Foo { }Dan B Wed 22 Jul 2020
I just tried the following; which results in the same compiler error.
| MicroTask[] Tasks, MicroTask Task->Bool | okayToRun okayToRun = | Foo[] Tasks, Foo Task->Bool | { Tasks.each | t | { if( t isnot Task ) { return false } } return true } ...Dan B Wed 22 Jul 2020
SlimerDude, thanks for the reply. I posted my second without first refreshing the page. I will try your solution.
The foo init was my mistake in creating the question. The real code has the correct int. I was trying to keep my question generic
Dan B Wed 22 Jul 2020
I don't think I have asked the question correctly or provided the correct background.
We have the following classes
Then in another class
private MicroTask?[] activeMicroTasks := MicroTask?[,].fill(null, 8) private MicroTask?[] delayedMicroTasks := MicroTask?[,].fill(null, 8) // Run a task for a particular micro internal Future? runMicroTask( MicroTask task, Bool checked := true, Bool autoStatus := true ) { // Input arg "task" can be one of: AutoConfigTask, AutoMatchTask, SyncConfigTask, or WireResistanceTask // Class variable "activeMicroTasks" will contain the "task" at the correct index later in this function. // I am trying to detect when runMicroTask is called with a different task type than what task type(s) // is contained in activeMicroTasks. // If it is different the incoming task is placed in delayedMicroTasks, to be run later ... }The type checking in the background function works as expected.
// Background function, runs periodically Void backgrouFunc() { ... else { // SAGE-1907: Maestro fails to send POST to start WR haveActive := activeMicroTasks.findAll | v | { v != null } haveDelayed := delayedMicroTasks.findAll | v | { v != null } // Do we have any task that were delayed? if( ( haveActive.size == 0 ) && ( haveDelayed.size > 0 ) ) { Device.log.info( "[BG Thread] delayedMicroTasks: $delayedMicroTasks ") delayedMicroTasks.each | MicroTask? m, Int j | { // Mark it as null so we don't repeat it delayedMicroTasks[ j ] = null if( m is SyncMicroConfigTask ){ syncConfigMicros.add( j ) } else if( m is AutoMatchTask ) { autoMatchMicros.add( j ) } else if( m is AutoConfigTask ) { autoConfigMicros.add( j ) } else if( m is WireResistanceTask ) { Device.log.info( "[BG Thread] Adding delayed WR task for micro $j" ) wireResistanceMicros.add( j ) } } } } }Dan B Wed 22 Jul 2020
My solution. Was hoping for something a little more elegant
haveSync := activeMicroTasks.any | v | { v != null && v is SyncMicroConfigTask } haveAC := activeMicroTasks.any | v | { v != null && v is AutoConfigTask } haveAM := activeMicroTasks.any | v | { v != null && v is AutoMatchTask } haveWR := activeMicroTasks.any | v | { v != null && v is WireResistanceTask } // There is active tasks. Now check the type of active // versus the requested (passed in) task if( ( ( haveSync ) && ( task isnot SyncMicroConfigTask ) ) || ( ( haveAC ) && ( task isnot AutoConfigTask ) ) || ( ( haveAM ) && ( task isnot AutoMatchTask ) ) || ( ( haveWR ) && ( task isnot WireResistanceTask ) ) ) { canRun = false } else { canRun = true }SlimerDude Wed 22 Jul 2020
I dunno, that logic looks kinda complicated to me...
I mean, if you wanted to reduce the code, you could loop over the types:
taskTypes := [SyncMicroConfigTask#, AutoConfigTask#, AutoMatchTask#, WireResistanceTask#] canRun := !taskTypes.any |taskType| { activeMicroTasks.any { it != null && it.typeof.fits(taskType) } && !task.fits(taskType) }But then I'd argue you loose a lot of readability as to what the code actually does... time to break out the unit tests!
Dan B Wed 22 Jul 2020
Yes, I like the readability of my solution
Dan B Fri 24 Jul 2020
Actually Jeremy provided a clean and readable solution.
haveActive := activeMicroTasks.findAll | v | { v != null } canRun := haveActive.any{ it.typeof.fits( task.typeof ) }brian Fri 24 Jul 2020
In the upcoming release there is also a findNotNull method. But one method that will filter out nulls and find a specific type is the
sys::List.findTypemethod:Which I think will collapse that to one line: