(Reinventing wheels can be fun, if the solution isn't too obvious. Perhaps you shouldn't be using this for real work, but OTOH, it's a bit like solving a crossword puzzle.)
I assume you want a tabstop per 8 characters? This appears to work, replacing each tab with a string of 1 to 8 spaces:
while(s/\t/" " x (8 - $-[0]%8)/e) {}
For example, in "a\tb", at the time of the replacement, $-[0] will be 1, so 7 spaces will be inserted, replacing the tab.
Note that s///g won't do the right thing, because it doesn't take into account the length of what's on the left of the match after any previous replacements; instead it'll continue to use the old length, as if nothing had been replaced yet. Thus, for the second match in "\t\t", $-[0] will still be 1, the length of the first "\t", and not 8, for the string of spaces that (already) replaced it.