Yeah the template language was kept simple so that logic would be necessarily kept out of the templates.
The best way to solve this is to create another small data handler method on your controller:
function MyList() {
$parent = DataObject::get_one('SiteTree', "URLSegment = 'my-page'");
return DataObject::get("SiteTree", "ParentID = $parent->ID", "", "", "4");
}
Then you can just use <% control MyList %> in your template.
The advantage of this approach is that you can focus on layout in your template file, and the exact details by which data is selected in your MyList() function. If you wanted to give template designers the flexibility to decide how many pages, to show, you could have an argument to the MyList function
function MyList($limit = 4) {
$parent = DataObject::get_one('SiteTree', "URLSegment = 'my-page'");
return DataObject::get("SiteTree", "ParentID = $parent->ID", "", "", $limit);
}
Then you can just use <% control MyList(4) %> in your template. Since we've set a default value for the $limit argument, you could also use <% control MyList %>.