Closed MohamedGhardallou closed 5 days ago
Hi, your suggestion contradicts the design choice to have no global variables in Blech. Here is a short example that explains why this would be a problem:
global x // to be written only by Filter, and read by all others
// ... some defitions of activities
activity Example()()
cobegin
run Filter()() // reads raw value, writes filtered value to global x
with
run Consumer()()
end
end
Above would be the architecture that you propose. Notice however that x
is not part of the API of the activities but used only implicitly. This introduces two problems:
x
is shared. This precludes separate compilation of activities and thereby breaks the module system.A solution to your problem might be to reconsider the design of your code. Note, that you do not have to read-in and filter the raw button value at the entry point activity. Instead you can use external inputs (https://www.blech-lang.org/docs/user-manual/declarations/#local-external-variables) in your Filter activity and then only the produced filtered value needs to be propagated. The question is then to how many different activities is it propagated and how deeply are they nested? In our experience so far, this was a negligible overhead. I hope this helps?
Hello, can't both readability and compilation issue be solved if we explicitly declare global variables inside activities that use them ?
for example this is sketch of my application:
activity filter()(start_btn : bool , limit_switch: bool )
@[CInput (binding = "start_btn", header = "board_io.h")]
extern let raw_start_btn: bool
@[CInput (binding = "limit_switch", header = "board_io.h")]
extern let raw_limit_switch: bool
cobegin
run FilterSignal(raw_start_btn)(start_btn)
with
run FilterSignal(raw_limit_switch)(limit_switch)
end
end
activity my_app(start_btn : bool , limit_switch: bool )()
repeat
let choice : nat8 = run voice_menu(start_btn)()
if choice == 1 then
run cycle_a(start_btn , limit_switch)()
else
run cycle_b(start_btn , limit_switch)()
end
end
end
@[EntryPoint]
activity Ctrl()()
var start_btn : bool = false
var limit_switch: bool = false
cobegin
run filter()(start_btn,limit_switch)
with
my_app(start_btn,limit_switch)()
end
end
if we use global input variables , i imagine something like this
activity filter()()
@[CInput (binding = "start_btn", header = "board_io.h")]
extern let raw_start_btn: bool
@[CInput (binding = "limit_switch", header = "board_io.h")]
extern let raw_limit_switch: bool
export global start_btn : bool
export global limit_switch : bool
cobegin
run FilterSignal(raw_start_btn)(start_btn)
with
run FilterSignal(raw_limit_switch)(limit_switch)
end
end
activity cycle_a()()
import global start_btn : bool
import global stop_btn : bool
// do something here
end
activity my_app()()
repeat
let choice : nat8 = run voice_menu()()
if choice == 1 then
run motor_cycle_1()()
else
run motor_cycle_2()()
end
end
end
@[EntryPoint]
activity Ctrl()()
cobegin
run filter()()
with
my_app()()
end
end
for my use case , i managed to have 4 nested level. I agree that this is manageable but maybe this can be addressed at the langage level without breaking blech clarity and simplicity.
This introduces two problems:
- Readability: ...
- Compilation: ...
Not to forget the third Problem
Activities using globals are singletons in our terminology, for which we take care in the compiler if they use external variables see: https://www.blech-lang.org/docs/language-evolution/blech-c-interface/env-variables/
Hello,
You cannot simply run an activity that uses a global from two different, concurrent run-calls in your application. Because both calls implicitly interact via the global variable
So i think that my statement was not clear. I am talking about "global input variable".
What i want to have is : a "singleton activity" that exclusively writes to a global variable and other "non singleton activities" that can only read this variable.
But even before talking about that , let's consider that i have a sensor value in my c program. and i want to make this variable available to every activity in my blech program ( without the need to pass it down from the entry activity )
What's the harm in declaring this variable as global input variable like this
@[CInput (binding = "theSensor", header = "sensors.h")]
extern let sensor: int8
activity cycle_a()()
// do something here with sensor
end
@[EntryPoint]
activity Ctrl()()
// do something here with sensor
run cycle_a()()
// ....
end
Sensor here can be considered as "module input variable" and it is updated each cycle.
As a side note we may also need to think about how to declare module input variable maybe we should not reference c header files directly to make module more reusable.
Nobody prevents you from using two or more extern let
that point to the same C variable.
Blech will copy-in the value within each tick.
activity cycle_a()()
@[CInput (binding = "theSensor", header = "sensors.h")]
extern let sensor: int8
// do something here with sensor
end
@[EntryPoint]
activity Ctrl()()
@[CInput (binding = "theSensor", header = "sensors.h")]
extern let sensor: int8
// do something here with sensor
run cycle_a()()
// ....
end
It is a "trick", but it should work
Hello
Is your feature request related to a problem? Please describe.
Imagine you have a button. the input signal needs to be filtered before using it in the application. without global variables , you will need to pass "down" this variable to every activity.
Describe the solution you'd like
I would like to be able to create an activity that produces a global variable. this variable will be written only by this activity but used by any other activity that needs it.
Describe alternatives you've considered we could try to define external "get" c function but then i want my logic to be written in blech.
Related why not also permit external input global variable ?
Thank you