Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

listop operator causing infinite recursion, any way to fix?

Tags:

raku

I'm looking to possibly help update the File::HomeDir module which was never finished. While inspecting it, I noticed that stubbed out methods were causing infinite loops:

In the File::HomeDir role:

unit class File::HomeDir;

use File::HomeDir::Win32;
use File::HomeDir::MacOSX;
use File::HomeDir::Unix;

my File::HomeDir $singleton;

method new
{
  return $singleton if $singleton.defined;
  
  if $*DISTRO.is-win {
    $singleton = self.bless does File::HomeDir::Win32;
  } elsif $*DISTRO.name.starts-with('macos') {
    $singleton = self.bless does File::HomeDir::MacOSX;
  } else {
    $singleton = self.bless does File::HomeDir::Unix;
  }

  return $singleton;
}

method my-home {
  return File::HomeDir.new.my-home;
}

method my-desktop {
  return File::HomeDir.new.my-desktop;
}

<snip>


In the File::HomeDir::MacOSX module:


use v6;

unit role File::HomeDir::MacOSX;

method my-home {
  # Try HOME on every platform first, because even on Windows, some
  # unix-style utilities rely on the ability to overload HOME.
  return %*ENV<HOME> if %*ENV<HOME>.defined;
  return;
}

method my-desktop {
  !!!
}

<snip>

With this code, calling say File::HomeDir.my-desktop; results in an infinite loop.

This module was first written about 5 1/2 years ago. I'm assuming it worked at the time. But it appears now that if a role method has a listop operator, it causes the parent's class to be called which then called the role method which then calls the parent class, etc.

like image 555
StevieD Avatar asked Sep 12 '25 14:09

StevieD


1 Answers

I'd do it like this, staying close to the original design:

role File::HomeDir::Win32 {
    method my-home()    { dd }
    method my-desktop() { dd }
}

role File::HomeDir::MacOSX {
    method my-home()    { dd }
    method my-desktop() { dd }
}

role File::HomeDir::Unix {
    method my-home()    { dd }
    method my-desktop() { dd }
}

class File::HomeDir {

    my $singleton;
    # Return singleton, make one if there isn't one already
    sub singleton() {
        without $singleton {
            $_ = File::HomeDir but $*DISTRO.is-win
              ?? File::HomeDir::Win32
              !! $*DISTRO.name.starts-with('macos')
                ?? File::HomeDir::MacOSX
                !! File::HomeDir::Unix;
        }
        $singleton
    }

    method my-home()    { singleton.my-home }
    method my-desktop() { singleton.my-desktop }
}

File::HomeDir.my-home;
File::HomeDir.my-desktop;
like image 106
Elizabeth Mattijsen Avatar answered Sep 16 '25 10:09

Elizabeth Mattijsen