Title: Commands get instantiated multiple times per run · Issue #476 · scijava/scijava-common · GitHub
Open Graph Title: Commands get instantiated multiple times per run · Issue #476 · scijava/scijava-common
X Title: Commands get instantiated multiple times per run · Issue #476 · scijava/scijava-common
Description: As discussed in this Zulip thread, when invoking a SciJava Command plugin, multiple instances of the command might get instantiated and then thrown away, just to retrieve default parameter values. This can create confusion if there is ac...
Open Graph Description: As discussed in this Zulip thread, when invoking a SciJava Command plugin, multiple instances of the command might get instantiated and then thrown away, just to retrieve default parameter values. ...
X Description: As discussed in this Zulip thread, when invoking a SciJava Command plugin, multiple instances of the command might get instantiated and then thrown away, just to retrieve default parameter values. ...
Opengraph URL: https://github.com/scijava/scijava-common/issues/476
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Commands get instantiated multiple times per run","articleBody":"As discussed in [this Zulip thread](https://imagesc.zulipchat.com/#narrow/stream/327495-scenery.2Bsciview/topic/Class.20initialization.20in.20Add.20commands), when invoking a SciJava `Command` plugin, multiple instances of the command might get instantiated and then thrown away, just to [retrieve default parameter values](https://github.com/scijava/scijava-common/blob/scijava-common-2.98.0/src/main/java/org/scijava/command/CommandModuleItem.java#L168). This can create confusion if there is actual business logic that gets executed during object construction, because it will then be executed multiple times, and if there are side effects, and/or performance implications, they will occur repeatedly.\r\n\r\n\u003cdetails\u003e\u003csummary\u003eStack trace illustrating the multiple instantiations\u003c/summary\u003e\r\n\r\n```\r\nBreakpoint reached at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\nBreakpoint reached\r\n at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\n at java.lang.invoke.DirectMethodHandle$Holder.newInvokeSpecial(DirectMethodHandle$Holder:-1)\r\n at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.invokeImpl(DirectConstructorHandleAccessor.java:86)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)\r\n at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)\r\n at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)\r\n at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)\r\n at java.lang.Class.newInstance(Class.java:725)\r\n at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:304)\r\n at org.scijava.command.CommandInfo.createInstance(CommandInfo.java:248)\r\n at org.scijava.command.CommandModule.instantiateCommand(CommandModule.java:248)\r\n at org.scijava.command.CommandModule.\u003cinit\u003e(CommandModule.java:98)\r\n at org.scijava.command.CommandInfo.createModule(CommandInfo.java:326)\r\n at org.scijava.module.DefaultModuleService.createModule(DefaultModuleService.java:167)\r\n at org.scijava.module.DefaultModuleService.run(DefaultModuleService.java:206)\r\n at org.scijava.module.DefaultModuleService.run(DefaultModuleService.java:197)\r\n at org.scijava.module.DefaultModuleService.run(DefaultModuleService.java:182)\r\n at org.scijava.menu.ShadowMenu.run(ShadowMenu.java:335)\r\n at org.scijava.ui.swing.menu.AbstractSwingMenuCreator$1.actionPerformed(AbstractSwingMenuCreator.java:169)\r\n...\r\nnow have 1 CountyThingies\r\nBreakpoint reached at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\nBreakpoint reached\r\n at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\n at java.lang.invoke.DirectMethodHandle$Holder.newInvokeSpecial(DirectMethodHandle$Holder:-1)\r\n at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.invokeImpl(DirectConstructorHandleAccessor.java:86)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)\r\n at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)\r\n at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)\r\n at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)\r\n at java.lang.Class.newInstance(Class.java:725)\r\n at org.scijava.command.CommandModuleItem.getDefaultValue(CommandModuleItem.java:168)\r\n at org.scijava.module.DefaultModuleService.getDefaultValue(DefaultModuleService.java:321)\r\n at org.scijava.module.process.DefaultValuePreprocessor.assignDefaultValue(DefaultValuePreprocessor.java:76)\r\n at org.scijava.module.process.DefaultValuePreprocessor.process(DefaultValuePreprocessor.java:61)\r\n at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)\r\n at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)\r\n at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)\r\n at org.scijava.thread.DefaultThreadService$$Lambda/0x0000000800f2ac68.call(Unknown Source:-1)\r\n at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:317)\r\n at java.util.concurrent.FutureTask.run(FutureTask.java:-1)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\r\n at java.lang.Thread.runWith(Thread.java:1596)\r\n at java.lang.Thread.run(Thread.java:1583)\r\nnow have 2 CountyThingies\r\nBreakpoint reached at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\nBreakpoint reached\r\n at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\n at java.lang.invoke.DirectMethodHandle$Holder.newInvokeSpecial(DirectMethodHandle$Holder:-1)\r\n at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.invokeImpl(DirectConstructorHandleAccessor.java:86)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)\r\n at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)\r\n at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)\r\n at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)\r\n at java.lang.Class.newInstance(Class.java:725)\r\n at org.scijava.command.CommandModuleItem.getDefaultValue(CommandModuleItem.java:168)\r\n at org.scijava.module.DefaultModuleService.getDefaultValue(DefaultModuleService.java:321)\r\n at org.scijava.module.process.DefaultValuePreprocessor.assignDefaultValue(DefaultValuePreprocessor.java:76)\r\n at org.scijava.module.process.DefaultValuePreprocessor.process(DefaultValuePreprocessor.java:61)\r\n at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)\r\n at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)\r\n at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)\r\n at org.scijava.thread.DefaultThreadService$$Lambda/0x0000000800f2ac68.call(Unknown Source:-1)\r\n at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:317)\r\n at java.util.concurrent.FutureTask.run(FutureTask.java:-1)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\r\n at java.lang.Thread.runWith(Thread.java:1596)\r\n at java.lang.Thread.run(Thread.java:1583)\r\nnow have 3 CountyThingies\r\nBreakpoint reached at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\nBreakpoint reached\r\n at sc.iview.commands.add.AddBox.\u003cinit\u003e(AddBox.kt:75)\r\n at java.lang.invoke.DirectMethodHandle$Holder.newInvokeSpecial(DirectMethodHandle$Holder:-1)\r\n at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.invokeImpl(DirectConstructorHandleAccessor.java:86)\r\n at jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)\r\n at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)\r\n at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)\r\n at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)\r\n at java.lang.Class.newInstance(Class.java:725)\r\n at org.scijava.command.CommandModuleItem.getDefaultValue(CommandModuleItem.java:168)\r\n at org.scijava.module.DefaultModuleService.getDefaultValue(DefaultModuleService.java:321)\r\n at org.scijava.module.process.DefaultValuePreprocessor.assignDefaultValue(DefaultValuePreprocessor.java:76)\r\n at org.scijava.module.process.DefaultValuePreprocessor.process(DefaultValuePreprocessor.java:61)\r\n at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)\r\n at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)\r\n at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)\r\n at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)\r\n at org.scijava.thread.DefaultThreadService$$Lambda/0x0000000800f2ac68.call(Unknown Source:-1)\r\n at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:317)\r\n at java.util.concurrent.FutureTask.run(FutureTask.java:-1)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\r\n at java.lang.Thread.runWith(Thread.java:1596)\r\n at java.lang.Thread.run(Thread.java:1583)\r\nnow have 4 CountyThingies\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\nOne idea to fix this would be to infer all of a command's default values the first time an instance is created as a module. Because an instance of the command *is* instantiated immediately: the one that is actually going to get run. The later ones are just throwaways. But if upon first instantiation, we inspected the instance's field values immediately and cached them into the `CommandInfo` itself, then we'd be able to reuse those values from the cache whenever `getDefaultValue()` is subsequently called, without instantiating throwaway instances.","author":{"url":"https://github.com/ctrueden","@type":"Person","name":"ctrueden"},"datePublished":"2024-03-19T14:45:34.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/476/scijava-common/issues/476"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:26666446-0cc3-f436-4e8f-641b12231774 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | CB00:3346BC:68DF5:8F460:6969C597 |
| html-safe-nonce | dcb5c00c1caa5763d1d581476e1b1eedb284e3bdc3c4a4d7ff38bddc8ba9bf56 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDQjAwOjMzNDZCQzo2OERGNTo4RjQ2MDo2OTY5QzU5NyIsInZpc2l0b3JfaWQiOiI1MDQ0ODkwMTk1NjMwNjA1NzE5IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | f957288232f9147e3a06df1a192f1c68ccb1cbc68ae80c29b49ffa8b883fcbf1 |
| hovercard-subject-tag | issue:2195176463 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/scijava/scijava-common/476/issue_layout |
| twitter:image | https://opengraph.githubassets.com/cd447af0f3384c5f4981fbdfc75041376bbdc0d4d1890418df135cbe8f22ef03/scijava/scijava-common/issues/476 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/cd447af0f3384c5f4981fbdfc75041376bbdc0d4d1890418df135cbe8f22ef03/scijava/scijava-common/issues/476 |
| og:image:alt | As discussed in this Zulip thread, when invoking a SciJava Command plugin, multiple instances of the command might get instantiated and then thrown away, just to retrieve default parameter values. ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | ctrueden |
| hostname | github.com |
| expected-hostname | github.com |
| None | acedec8b5f975d9e3d494ddd8f949b0b8a0de59d393901e26f73df9dcba80056 |
| turbo-cache-control | no-preview |
| go-import | github.com/scijava/scijava-common git https://github.com/scijava/scijava-common.git |
| octolytics-dimension-user_id | 1262770 |
| octolytics-dimension-user_login | scijava |
| octolytics-dimension-repository_id | 3594497 |
| octolytics-dimension-repository_nwo | scijava/scijava-common |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 3594497 |
| octolytics-dimension-repository_network_root_nwo | scijava/scijava-common |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 83c08c21cdda978090dc44364b71aa5bc6dcea79 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width