Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungBreeze TTS 2 vs ElevenLabs: Open Source TTS Verdict(23.09.2026 um 05:44 Uhr)
Sichere ProgrammierungAgentic AI vs Generative AI: The 2026 Verdict(23.09.2026 um 05:44 Uhr)
Sichere ProgrammierungI made my agent prove every quote against the source document(23.09.2026 um 05:45 Uhr)
Sichere Programmierung8mb.video Alternative: Skip the Line, Skip the Upsell(23.09.2026 um 05:47 Uhr)
Sichere ProgrammierungBuilding a GTA 6 JSON API for entities and current status(23.09.2026 um 05:52 Uhr)
Sichere ProgrammierungEvery filter needs a documented exception(23.09.2026 um 06:01 Uhr)
Sichere ProgrammierungBreeze TTS 2 vs ElevenLabs: Open Source TTS Verdict(23.09.2026 um 05:44 Uhr)
Sichere ProgrammierungAgentic AI vs Generative AI: The 2026 Verdict(23.09.2026 um 05:44 Uhr)
Sichere ProgrammierungI made my agent prove every quote against the source document(23.09.2026 um 05:45 Uhr)
Sichere Programmierung8mb.video Alternative: Skip the Line, Skip the Upsell(23.09.2026 um 05:47 Uhr)
Sichere ProgrammierungBuilding a GTA 6 JSON API for entities and current status(23.09.2026 um 05:52 Uhr)
Sichere ProgrammierungEvery filter needs a documented exception(23.09.2026 um 06:01 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Learning XS - List context

Over the past year, I’ve been self-studying XS and have now decided to share my learning journey through a series of blog posts. This third post introduces you to list context in XS. What do I mean by list context? In Perl, there are two …

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Over the past year, I’ve been self-studying XS and have now decided to share my learning journey through a series of blog posts. This third post introduces you to list context in XS.



What do I mean by list context?



In Perl, there are two main contexts in which a function can be called: scalar context and list context. Scalar context means that the function is expected to return a single value, while list context means that the function is expected to return a list of values.



In XS, list context is a bit more complex than scalar context. When a function is called in list context, it can return multiple values, so in XS you need to push each value onto the stack. This is done by manipulating ST and using the 'XSRETURN' macro, which takes the number of values to return as an argument. I will demonstrate how all of this works in our next example.



Today we are going to build a simple OO shopping list module. We will port the following perl code:




package Shopping::List;

sub new {
my ($pkg, @args) = @_;
my %list;
$list{$_}++ for @args;
return bless \%list, $pkg;
}

sub add {
my ($self, @items) = @_;
$self->{$_}++ for @items;
return @items;
}

sub remove {
my ($self, @items) = @_;
my @deleted;
push(@deleted, $_) && delete $self->{$_} for @items;
return \@deleted;
}

sub items {
my ($self) = @_;
return %$self;
}

1;






You can then call it like this:




use Shopping::List;
my $list = Shopping::List->new('apple', 'banana', 'carrot');
$list->add('date', 'eggplant', 'apple');
$list->remove('banana', 'carrot');
$list->items;






As you can see, in Perl list context is simple, in XS we have to do a bit more work. Let’s start by creating a new distribution 'Shopping::List'. We again will use 'Module::Starter' to create the distribution structure:




module-starter --module="Shopping::List" --author="Your Name" --email="your email"






Update the Makefile.PL to include XSMULTI => 1, and then open the generated Shopping/List.pm file to update the boiler plate code to the following:




package Shopping::List;

use 5.006;
use strict;
use warnings;

our $VERSION = '0.01';

require XSLoader;
XSLoader::load('Shopping::List', $VERSION);

1;






Next we will create the skeleton XS file. Create a new file called 'Shopping/List.xs' and add the following code:




#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

MODULE = Shopping::List PACKAGE = Shopping::List
PROTOTYPES: DISABLE

SV*
new(pkg, ...)
SV * pkg
CODE:
HV *hash = newHV();
RETVAL = sv_bless(newRV_noinc((SV*)hash), gv_stashsv(pkg, 0));
OUTPUT:
RETVAL






When defining new we have defined pkg as a required variable and used the ... for optional arguments, this signals to perl that our method can be called in list context.



With that in place we can build the distribution to ensure everything is set up correctly:




perl Makefile.PL
make
make test






Next lets write a quick test for the first method which we will implement, which is the 'new' method. Create a new file called 't/01-shopping-list.t':




use Test::More;

use Shopping::List;

my $list = Shopping::List->new('apple', 'banana', 'carrot');
is_deeply($list, { apple => 1, banana => 1, carrot => 1 }, 'Shopping list created with initial items');






Now lets actually implement the method inside 'Shopping/List.xs' update new to:




SV*
new(pkg, ...)
SV * pkg
CODE:
HV *hash = newHV();
int i = 1;
for (; i < items; i++) {
SV *item = ST(i);
if (SvTYPE((item)) < SVt_PVAV) {
STRLEN retlen;
char *key = SvPV(item, retlen);
if (hv_exists(hash, key, retlen)) {
int current = SvIV(hv_fetch(hash, key, retlen, 0));
hv_store(hash, key, retlen, newSViv(current + 1), 0);
} else{
hv_store(hash, key, retlen, newSViv(1), 0);
}
}
}
RETVAL = sv_bless(newRV_noinc((SV*)hash), gv_stashsv(pkg, 0));
OUTPUT:
RETVAL






If you now run the test again it will pass. What we are doing is using 'items', which is a special variable in XS that contains the number of items passed to the function. When iterating over the items, we start our count at 1 because 0 is pkg. Inside the for loop we check if the item is a string by using SvTYPE and checking whether its less than the value of an Array aka a scalar, and if it is, we then check if it already exists in the hash. If it does, we increment the count, otherwise we add it with a count of 1.



Next we will write another test for the 'add' method, which will return in list context the list which is passed.




my @added = $list->add('date', 'eggplant', 'apple');
is_deeply(\@added, ['date', 'eggplant', 'apple']);
is_deeply($list, { apple => 2, banana => 1, carrot => 1, date => 1, eggplant => 1 });






And the code to implement this method in 'Shopping/List.xs':




SV*
add(self, ...)
SV * self
CODE:
HV *hash = (HV*)SvRV(self);
int i = 1;
for (; i < items; i++) {
SV *item = ST(i);
if (SvTYPE((item)) < SVt_PVAV) {
STRLEN retlen;
char *key = SvPV(item, retlen);
if (hv_exists(hash, key, retlen)) {
int current = SvIV(*hv_fetch(hash, key, retlen, 0));
hv_store(hash, key, retlen, newSViv(current + 1), 0);
} else{
hv_store(hash, key, retlen, newSViv(1), 0);
}
}
SvREFCNT_inc(item);
ST(i - 1) = item;
}

XSRETURN(i - 1);






If we step through this, we first get the hash reference from the self object, then we iterate over the items passed to the function. For each item, we check if it is a string and if it exists in the hash. If it does, we increment the count, otherwise we add it with a count of 1. After that, we increment the reference count of the item and move it one position left on the stack. Finally, we return the number of items pushed onto the stack using 'XSRETURN'. we use the variable 'i' - 1(pkg) as this is our total count of items processed. Note also we do not have an OUTPUT or RETVAL defined, this is not needed when returning a list context with XSRETURN. Now if you run the test again it will pass, so lets add another test for remove.




my @removed = $list->remove('banana', 'carrot');
is_deeply(\@removed, ['banana', 'carrot']);
is_deeply($list, { apple => 2, date => 1, eggplant => 1 });






Then the code to implement this method in 'Shopping/List.xs':




SV*
remove(self, ...)
SV * self
CODE:
HV *hash = (HV*)SvRV(self);
int i = 1;
for (; i < items; i++) {
SV *item = ST(i);
if (SvTYPE((item)) < SVt_PVAV) {
STRLEN retlen;
char *key = SvPV(item, retlen);
if (hv_exists(hash, key, retlen)) {
hv_delete(hash, key, retlen, 0);
}
}
SvREFCNT_inc(item);
ST(i - 1) = item;
}

XSRETURN(i - 1);






Again if we step through this, we first get the hash reference from the self object, then we iterate over the items passed to the function. For each item, we check if it is a string and if it exists in the hash. If it does, we delete it from the hash. After that, we increment the reference count of the item and move it one position left on the stack. Finally, we return the number of items pushed onto the stack using 'XSRETURN'.



Finally, lets add the items method test:




my %list = $list->items();
is_deeply(\%list, { apple => 2, date => 1, eggplant => 1 });






We will take a slightly different approach this time, add this code to implement the items method in 'Shopping/List.xs':




SV*
items(self)
SV * self
CODE:
POPs;
HV *hash = (HV*)SvRV(self);
HE *item;
int count = hv_iterinit(hash);
EXTEND(SP, count * 2);
while ((item = hv_iternext(hash))) {
SV *key = hv_iterkeysv(item);
SV *value = hv_iterval(hash, item);
SvREFCNT_inc(key);
SvREFCNT_inc(value);
PUSHs(key);
PUSHs(value);
}
XSRETURN(count * 2);






To explain this, we first pop the self object from the stack, then we get the hash reference from the self object. We then initialize an iterator for the hash and extend the stack to accommodate the number of items in the hash. We then iterate over each item in the hash, getting both the key and value, incrementing their reference counts, and pushing them onto the stack. Finally, we return the count of items multiplied by 2 (as we are returning both keys and values).



Now if you run the test again it will pass, and we have a fully functional shopping list module in XS that supports list context.



In the next blog I will cover overloading methods.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Learning XS - List context

Thematisch verwandte Begriffe: Learning, List, context · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-18163 | IBM Financial Transaction Manager (FTM) for RedHat OpenShift could allow…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick