nevalang / neva

🌊 Dataflow programming language with static types and implicit parallelism. Compiles to native code and Go
https://nevalang.org
MIT License
85 stars 7 forks source link

Static inports #256

Closed emil14 closed 1 year ago

emil14 commented 1 year ago

This issue describes 4 problems with current design of static messages

  1. There's no way to use selectors with static messages right now
  2. Keeping them in nodes leads to a special case (there's no incoming connections to inports bound to messages)
  3. And a bit less intuitive nodes structure (node and instance types instead of just node)
  4. There's special giver routine and because of that we have to have not just runtime functions but the more abstract routines of 2 kinds


    Less intuitive program structure

That complexity will go otherwise from nodes to network because we gonna introduce some second type (or is there another way?) of a incoming connection. It's like there will be "normal connection to an outport" and "connection to a message"

There's special giver routine and because of that we have to have not just runtime functions but the more abstract routines of 2 kinds

On the other hand there's a way to introduce more types of routines that way (not sure actually that's a good idea)

There's no way to use selectors with static messages right now...

in order to use selectors we have to either

Moving to network will also fix 2 and 3 problems

There's special giver routine and because of that we have to have not just runtime functions

There's only one way to fix this - get rid of routines and givers as a concept and create a runtime function that could serve the same purpose - send predefined messages across specified inports throughout the network.

(For historical purposes - the "giver" issue was discussed in #161 and #106).

emil14 commented 1 year ago

Giver runtime function and context.Context

This one only fixes number 4 problem

There already was an idea of using ctx as a extendable part of the runtime functions so why don't we just use it to pass a message, or a map of messages, or any other container (if container needed (we probably want less givers than more givers))

Problem 1. Performance

Spawning goroutines that sends messages is obviously cheaper than spawning goroutines that reads values from ctx and only then sends them. On the other hand - this only happens at startup. Is performance penalty big enough so we don't wanna get rid of everything except runtime functions?

Problem 2. How to implement?

Who's gonna pass msg to ctx? There's only one place - func runner. That means there should be some logic like "spawn functions but sometimes insert msg into ctx". That "sometimes" must be implemented somehow like this

runtimeFunc {
  msg Msg // only make sense for giver component
  ...
}

That's obviously bad design and current solution with routines and giverRoutine is better


155 #165

emil14 commented 1 year ago

Move staticPorts to network. Option 1. Duality port | msg and almost no changes

Just remove staticPorts from nodes and try to reuse existing structure as-is without changing anything. There will be some if in the code like "if it points to a message, not component, then it's a static-port".

Let's take a look at current structure:

type Connection struct {
    SenderSide    ConnectionSide
    ReceiverSides []ConnectionSide
}

type ConnectionSide struct {
    PortAddr  ConnPortAddr
    Selectors []Selector
}

type ConnPortAddr struct {
    Node string // and this probably should be package
    RelPortAddr
}

type RelPortAddr struct {
    Name string // this probably should be a message name
    Idx  uint8 // this have no use for static message (not even for arrays, at least because we want selectors)
}

So at the end of the day we end up with something like

type ConnectionSideRef struct {
    NodeOrPkg string
    LocalRef
}

type LocalRef struct {
    PortNameOrPkg string
    Idx  uint8 // not used for messages
}

Problem

It's possible to end up with better naming but it's obvious to me that this is a bad design

emil14 commented 1 year ago

Move staticPorts to network. Option 2. Express duality explicitly

type Connection struct {
    SenderSide    SenderConnectionSide
    ReceiverSides []ReceiverConnectionSide
}

type SenderConnectionSide struct {
    PortAddr  ConnPortAddr
    Selectors []Selector
}

type Selector struct {
    RecField string // "" means use ArrIdx
    ArrIdx   int
}

type ConnPortAddr struct {
    Node string
    RelPortAddr
}

type RelPortAddr struct {
    Name string
    Idx  uint8
}

type ReceiverConnectionSide struct { // === New code === 
    Msg *Msg // non nil msg means static port
    PortAddr  ConnPortAddr
    Selectors []Selector
}

Interpretation part of this data can make obvious decisions like "if there's a message then add IR giver and connect it ti that port"

emil14 commented 1 year ago

Closed due to choosing https://github.com/nevalang/nevalang/issues/256#issuecomment-1489020579