This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
MKlegoman357's profile picture

A Question to Dan200 about Multishell tab IDs

Started by MKlegoman357, 03 October 2014 - 04:06 PM
MKlegoman357 #1
Posted 03 October 2014 - 06:06 PM
Hello, Dan200,

I probably should have asked this months ago, but here's what I found.

As soon as CC 1.6 was released I went to check how you did the multishell system by opening the 'rom/programs/advanced/multishell' file. After examining it, I found one thing about the programs' IDs and how they are assigned and managed.

Imagine this scenario: I run program A and, before it ends, run program B and capture it's tab ID. Now, program A ends, but program B is still running. Lets say I then want to change the title of the program B using the ID I captured before. I call all functions correctly, but the title doesn't change no matter what I do.

The title didn't change, because when program A ended, program B's ID changed.

Now, to prove this, I made these two programs:

test:

print("testing ")

local s = tonumber(...)

if s then
  sleep(s)
end

run:

local id1 = multishell.launch({}, "test", 1)
local id2 = multishell.launch({}, "test", 10)

multishell.setTitle(id2, "test2")
multishell.setFocus(id2)

print("ID 1: ", id1)
print("ID 2: ", id2)

sleep(5)

multishell.setTitle(id2, "testing")

print("ID 2: ", multishell.getFocus())

Reproduction steps:
  1. Put both programs in the root directory of the computer. Make sure the first program is named 'test'.
  2. Run the second program ('run').
  3. Quickly open the tab named 'test' and press any key when it asks you to, to close the program.
  4. Now, quickly switch to the tab named 'test2' and wait until it exits.

If you have run everything correctly, the end result should look something like this:

Spoiler

The reason the ID changes is because of how tabs and their IDs are stored inside multishell. Tabs are stored in one table. Each tab is inserted using table.insert and removed using table.remove. The ID of the tab is the index of it in the table.

My question is: is this an intentional design feature or an unwanted bug?

To me, it looks like Dan200 simply didn't notice this problem.

BTW, how do I summon Dan200 to answer my question :D/>/> because I don't think he comes here often.
Edited on 03 October 2014 - 04:08 PM
Lyqyd #2
Posted 03 October 2014 - 07:41 PM
You don't really "summon" dan himself to answer your questions. He didn't overlook this problem. You should use multishell.getCurrent() to get the current ID number for the tab prior to setting the title.
MKlegoman357 #3
Posted 03 October 2014 - 09:57 PM
multishell.getCurrent() gets the running program's ID, not the other program's ID. For now, there's no big reason to make tabs have static IDs, but who knows, maybe in the future some things will change and it will be easier to manage your programs by having their static IDs. Also, setting the title was just an example, there might be other uses for the IDs.
Edited on 03 October 2014 - 07:57 PM
Lyqyd #4
Posted 04 October 2014 - 01:14 AM
Well, in this specific contrived example, you could probably iterate the list to find the title you want, then change it, at least if it's the only one.

I can't think of a use for changing the title of another tab any time later than immediately after starting it, though. Why are you wanting to do this? Why can't the program change its own tab title?
Bomb Bloke #5
Posted 04 October 2014 - 02:11 AM
How can a script change its own tab title if there's no reliable method of getting its own tab ID?

The best you can do is search for a tab with a specific title, and assume that's the one you want to mess with (hoping, of course, that no two tabs have the same title.) Alternatively, you can rig a script to always assume that it's in the "current" tab. Both of these methods involve making assumptions, however the chance for error is fairly low if rigged correctly.

While it's a niche case, it does strike me that static tab IDs would be an all-round improvement though. Faster for one thing.

A rather tricky issue with multishell (which was pointed out before 1.6 left beta) is API/rednet management. If one tab opens rednet for eg, it has no way of knowing whether other tabs still want it accessible when it finishes up. Sure, a script can take a guess based on what features were already in use when it loaded, but what if other scripts started after it did…? Scripts that clean up after themselves may break others.
Lyqyd #6
Posted 04 October 2014 - 02:34 AM
The multishell.current() function returns the tab ID for the currently running tab, i.e., its own tab ID. The problem OP is having is that he wants to change a different tab's title, which I'm having difficulty understanding the use case for.

Funny enough, LyqydOS does actually go out of its way to handle the modem management issue you mention. :)/> There isn't anything out there intended to fix multishell as far as I know, though.
Bomb Bloke #7
Posted 04 October 2014 - 02:46 AM
The multishell.current() function returns the tab ID for the currently running tab, i.e., its own tab ID.

Ah, I'd gone and mixed it up with multishell.getFocus(). My bad.

I believe MKlegoman357 has no use case and is simply using tab renaming as an example to point out a potential issue. Use of multishell.setFocus() is much more likely to encounter problems.
Hiran #8
Posted 04 October 2014 - 12:49 PM
How can a script change its own tab title if there's no reliable method of getting its own tab ID?

The best you can do is search for a tab with a specific title, and assume that's the one you want to mess with (hoping, of course, that no two tabs have the same title.) Alternatively, you can rig a script to always assume that it's in the "current" tab. Both of these methods involve making assumptions, however the chance for error is fairly low if rigged correctly.

While it's a niche case, it does strike me that static tab IDs would be an all-round improvement though. Faster for one thing.

A rather tricky issue with multishell (which was pointed out before 1.6 left beta) is API/rednet management. If one tab opens rednet for eg, it has no way of knowing whether other tabs still want it accessible when it finishes up. Sure, a script can take a guess based on what features were already in use when it loaded, but what if other scripts started after it did…? Scripts that clean up after themselves may break others.

If i start developing that my PDA override project ill have to beware of things like that. Are there any other tricky issues with multishell? And do you have any idea how to fix them?

Edit:
And for that rednet.. i didn't analyze its code yet, but easiest idea would be to create something like "shared_ptr" class in C++. shared_ptr object will only call "delete" on the pointer its using if number of instances is 1, so you can be sure that nothing else uses it.
Edited on 04 October 2014 - 10:55 AM
MKlegoman357 #9
Posted 04 October 2014 - 01:00 PM
I believe MKlegoman357 has no use case and is simply using tab renaming as an example to point out a potential issue.

Exactly.

In my opinion, programs having static IDs would make much more sense. There would be a little bit more sense to capture and maybe use those IDs later. It would actually be nice if we could destroy processes using their IDs. Maybe even a communication system between different programs. But for those two things to exist, programs should have static IDs.

If i start developing that my PDA override project ill have to beware of things like that. Are there any other tricky issues with multishell? And do you have any idea how to fix them?

I'm not aware of any other 'issues' of multishell. Though, the fix/improvement regarding the ID 'issue' would be very simple:


--// Replace this:
table.remove( tProcesses, nProcess )

--// With this:
tProcesses[ nProcess ] = nil

--// Change all these:
#tProcesses

--// With this (depends on how you do it):
mutlishell.getCount()
--or
getCount()

--// And change multishell.getCount() to something like this:
function multishell.getCount()
    local count = 0

    for id, proc in pairs(tProcesses) do
        count = count + 1
    end

    return count
end

There might be other things that would have to be changed but the idea is, that it is a simple fix/improvement.
Bomb Bloke #10
Posted 04 October 2014 - 01:32 PM
Bear in mind that table.maxn(tProcesses) can be used to get the highest index in tProcesses, gaps or no. It is slow, though, so a tracking variable would be better.

Dan's more than capable of dealing with it if he wants to, though. Guy's code often makes me feel guilty about my own lack of micro-optimisations.

If i start developing that my PDA override project ill have to beware of things like that. Are there any other tricky issues with multishell? And do you have any idea how to fix them?

Other than those listed here, nothing comes to mind. Other than it being slow, but that can't really be helped. ;)/>
Edited on 04 October 2014 - 11:36 AM
Hiran #11
Posted 04 October 2014 - 01:40 PM
Hmm ill probably have to disable it on normal computers. Things could get really messy if it were to be used with peripherals.
Edit:
In my opinion, programs having static IDs would make much more sense. There would be a little bit more sense to capture and maybe use those IDs later. It would actually be nice if we could destroy processes using their IDs. Maybe even a communication system between different programs. But for those two things to exist, programs should have static IDs.
Im planning to implement just that :)/> both communication using events & a easy way to kill process.
Edited on 04 October 2014 - 12:04 PM