Rocksolid Light

News from da outaworlds

mail  files  register  groups  login

Message-ID:  

BOFH excuse #372: Forced to support NT servers; sysadmins quit.


comp / comp.lang.tcl / how to create a simple closure to create validators

SubjectAuthor
* how to create a simple closure to create validatorsMark Summerfield
+* Re: how to create a simple closure to create validatorset99
|`- Re: how to create a simple closure to create validatorsMark Summerfield
`- Re: how to create a simple closure to create validatorsJoerg Mertens

1
Subject: how to create a simple closure to create validators
From: Mark Summerfield
Newsgroups: comp.lang.tcl
Date: Thu, 20 Jun 2024 07:59 UTC
Path: eternal-september.org!news.eternal-september.org!feeder3.eternal-september.org!border-3.nntp.ord.giganews.com!nntp.giganews.com!local-3.nntp.ord.giganews.com!Xl.tags.giganews.com!local-2.nntp.ord.giganews.com!nntp.brightview.co.uk!news.brightview.co.uk.POSTED!not-for-mail
NNTP-Posting-Date: Thu, 20 Jun 2024 07:59:24 +0000
From: mark@qtrac.eu (Mark Summerfield)
Subject: how to create a simple closure to create validators
Newsgroups: comp.lang.tcl
MIME-Version: 1.0
User-Agent: Pan/0.154 (Izium; 517acf4)
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Message-ID: <sMicnWfm8djBfO77nZ2dnZfqnPWdnZ2d@brightview.co.uk>
Date: Thu, 20 Jun 2024 07:59:24 +0000
Lines: 65
X-Usenet-Provider: http://www.giganews.com
X-Trace: sv3-12Y+T6HXGY/cBvhL0MsO64yELYzuc3VO//iFANgwjXDyzfoPapThKcXOD5w0lRYddfruihNjIHmtJou!YfMzdNM5a8rgNWXlVllC58xIFJXpSHVw2Sk6HMAnChixiYW3C9fSQXV072ZpKtVWsIu5V/v1yt1g!nbmJA/gTtsK4U/xDSWBqEG/UVQ==
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.40
View all headers

I can make a variable that has a specific validator quite easily using
trace add.

But I can't work out how to create a validator maker (i.e., a simple
closure).

I am using Tcl/Tk 9.0b2.

Here is the code:

#!/usr/bin/env tclsh9

proc valid_percent {varname elemname op} {
upvar 1 $varname var
if {$op eq "write"} {
if {$var < 0} {
set var 0
} elseif {$var > 100} {
set var 100
}
}
}

proc check {expected actual} {
if {$expected != $actual} {
puts "ERROR $expected != $actual"
} else {
puts "OK $expected == $actual"
}
}

trace add variable percent write valid_percent

set percent 50
check 50 $percent
set percent -5
check 0 $percent
set percent 492
check 100 $percent

# All the above works correctly; what's below fails with:
# can't read "min": no such variable

proc clamper {min max} {
proc clamp {varname elemname op} {
upvar 1 $varname var
if {$op eq "write"} {
if {$var < $min} {
set var $min
} elseif {$var > $max} {
set var $max
}
}
}
return clamp
}

trace add variable score write [clamper 0 20]

set score 15
check 15 $score
set score -5
check 0 $score
set score 25
check 20 $score

Subject: Re: how to create a simple closure to create validators
From: et99
Newsgroups: comp.lang.tcl
Organization: A noiseless patient Spider
Date: Thu, 20 Jun 2024 18:59 UTC
References: 1
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: et99@rocketship1.me (et99)
Newsgroups: comp.lang.tcl
Subject: Re: how to create a simple closure to create validators
Date: Thu, 20 Jun 2024 11:59:38 -0700
Organization: A noiseless patient Spider
Lines: 121
Message-ID: <v51u6q$2n0bl$1@dont-email.me>
References: <sMicnWfm8djBfO77nZ2dnZfqnPWdnZ2d@brightview.co.uk>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 20 Jun 2024 20:59:39 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="4bfb749472245387d7ca1d936b6fd305";
logging-data="2851189"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19+/D4RAUDUh8BiA1Bvkg9L"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101
Thunderbird/102.6.1
Cancel-Lock: sha1:VJ+z+DE7aw6BgW1VPNXh37Wlr6Q=
Content-Language: en-US
In-Reply-To: <sMicnWfm8djBfO77nZ2dnZfqnPWdnZ2d@brightview.co.uk>
View all headers

On 6/20/2024 12:59 AM, Mark Summerfield wrote:
> I can make a variable that has a specific validator quite easily using
> trace add.
>
> But I can't work out how to create a validator maker (i.e., a simple
> closure).
>
> I am using Tcl/Tk 9.0b2.
>
> Here is the code:
>
> #!/usr/bin/env tclsh9
>
> proc valid_percent {varname elemname op} {
> upvar 1 $varname var
> if {$op eq "write"} {
> if {$var < 0} {
> set var 0
> } elseif {$var > 100} {
> set var 100
> }
> }
> }
>
> proc check {expected actual} {
> if {$expected != $actual} {
> puts "ERROR $expected != $actual"
> } else {
> puts "OK $expected == $actual"
> }
> }
>
> trace add variable percent write valid_percent
>
> set percent 50
> check 50 $percent
> set percent -5
> check 0 $percent
> set percent 492
> check 100 $percent
>
> # All the above works correctly; what's below fails with:
> # can't read "min": no such variable
>
> proc clamper {min max} {
> proc clamp {varname elemname op} {
> upvar 1 $varname var
> if {$op eq "write"} {
> if {$var < $min} {
> set var $min
> } elseif {$var > $max} {
> set var $max
> }
> }
> }
> return clamp
> }
>
> trace add variable score write [clamper 0 20]
>
> set score 15
> check 15 $score
> set score -5
> check 0 $score
> set score 25
> check 20 $score

Here's how I might do this:

proc validateRange {min max name1 name2 op} {
if { $name2 eq "" } { ;# scalar
upvar 1 $name1 newValue
if { $newValue < $min } {
set newValue $min
} elseif { $newValue > $max } {
set newValue $max
}
} else { ;# array - left as exercise for reader

}
}

trace add variable my_percent write {validateRange 0 20 }

set my_percent 10
puts "my_percent= |$my_percent| was 10"
set my_percent 50
puts "my_percent= |$my_percent| was 50"
set my_percent -50
puts "my_percent= |$my_percent| was -50"

trace add variable my_percent100 write {validateRange 5 100 }

set my_percent100 10
puts "my_percent100= |$my_percent100| was 10"
set my_percent100 500
puts "my_percent100= |$my_percent100| was 500"
set my_percent100 -50
puts "my_percent100= |$my_percent100| was -50"

output:

my_percent= |10| was 10
my_percent= |20| was 50
my_percent= |0| was -50
my_percent100= |10| was 10
my_percent100= |100| was 500
my_percent100= |5| was -50

Subject: Re: how to create a simple closure to create validators
From: Joerg Mertens
Newsgroups: comp.lang.tcl
Organization: A noiseless patient Spider
Date: Thu, 20 Jun 2024 19:48 UTC
References: 1
Path: eternal-september.org!news.eternal-september.org!jmertens.eternal-september.org!.POSTED!not-for-mail
From: joerg-mertens@t-online.de (Joerg Mertens)
Newsgroups: comp.lang.tcl
Subject: Re: how to create a simple closure to create validators
Date: Thu, 20 Jun 2024 21:48:16 +0200
Organization: A noiseless patient Spider
Lines: 25
Message-ID: <v52121$2nk3i$1@jmertens.eternal-september.org>
References: <sMicnWfm8djBfO77nZ2dnZfqnPWdnZ2d@brightview.co.uk>
Injection-Date: Thu, 20 Jun 2024 21:48:19 +0200 (CEST)
Injection-Info: jmertens.eternal-september.org; posting-host="771adc053cdf02aecc8681ba4546e3e3";
logging-data="2871419"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18y4o7bsM8m89CM848OJuyT/+m5xzJLEVs="
User-Agent: tin/2.6.2-20221225 ("Pittyvaich") (OpenBSD/7.5 (amd64)) tinews.pl/1.1.61
Cancel-Lock: sha1:Ku6EE53soySLBd2MOba5hX+/yzY=
View all headers

Mark Summerfield <mark@qtrac.eu> wrote:

> proc clamper {min max} {
> proc clamp {varname elemname op} {
> upvar 1 $varname var
> if {$op eq "write"} {
> if {$var < $min} {
> set var $min
> } elseif {$var > $max} {
> set var $max
> }
> }
> }
> return clamp
> }

To add to what others have said: Tcl doesn't have nested procedures.
"clamp" will just be another toplevel procedure, so it won't have
access to the arguments of "clamper". It also means, that "clamp"
will be overwritten with every call to "clamper".

There are also no lexical scopes inside of procedures and therefore
no lexical closures. So most Lisp patterns won't work here.

Regards

Subject: Re: how to create a simple closure to create validators
From: Mark Summerfield
Newsgroups: comp.lang.tcl
Date: Fri, 21 Jun 2024 09:43 UTC
References: 1 2
Path: eternal-september.org!news.eternal-september.org!feeder3.eternal-september.org!border-2.nntp.ord.giganews.com!local-1.nntp.ord.giganews.com!border-3.nntp.ord.giganews.com!nntp.giganews.com!local-3.nntp.ord.giganews.com!Xl.tags.giganews.com!local-2.nntp.ord.giganews.com!nntp.brightview.co.uk!news.brightview.co.uk.POSTED!not-for-mail
NNTP-Posting-Date: Fri, 21 Jun 2024 09:43:00 +0000
From: mark@qtrac.eu (Mark Summerfield)
Subject: Re: how to create a simple closure to create validators
Newsgroups: comp.lang.tcl
References: <sMicnWfm8djBfO77nZ2dnZfqnPWdnZ2d@brightview.co.uk>
<v51u6q$2n0bl$1@dont-email.me>
MIME-Version: 1.0
User-Agent: Pan/0.154 (Izium; 517acf4)
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Message-ID: <RJ-dnbImWOe51uj7nZ2dnZfqnPWdnZ2d@brightview.co.uk>
Date: Fri, 21 Jun 2024 09:43:00 +0000
Lines: 111
X-Usenet-Provider: http://www.giganews.com
X-Trace: sv3-zqlmEc2iO4i3CzXvAWhB0Erf20Q9t25IRoabun6q14VYG4JUxV/jU4uTPiQCZNykAqCgAB/kIpf5KfQ!ETVeAeLOBlx6KehnM/DZQFyKDi0EkabgvKG0zj3g44TQCtKeVGUBRYn4d+WDVAZE2ibenELkmNAj!2ZyRNRHBDDntl7nfbI2ZEmmKBw==
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.40
View all headers

On Thu, 20 Jun 2024 11:59:38 -0700, et99 wrote:

> On 6/20/2024 12:59 AM, Mark Summerfield wrote:
>> I can make a variable that has a specific validator quite easily using
>> trace add.
>>
>> But I can't work out how to create a validator maker (i.e., a simple
>> closure).
>>
>> I am using Tcl/Tk 9.0b2.
>>
>> Here is the code:
>>
>> #!/usr/bin/env tclsh9
>>
>> proc valid_percent {varname elemname op} {
>> upvar 1 $varname var if {$op eq "write"} {
>> if {$var < 0} {
>> set var 0
>> } elseif {$var > 100} {
>> set var 100
>> }
>> }
>> }
>>
>> proc check {expected actual} {
>> if {$expected != $actual} {
>> puts "ERROR $expected != $actual"
>> } else {
>> puts "OK $expected == $actual"
>> }
>> }
>>
>> trace add variable percent write valid_percent
>>
>> set percent 50 check 50 $percent set percent -5 check 0 $percent set
>> percent 492 check 100 $percent
>>
>> # All the above works correctly; what's below fails with:
>> # can't read "min": no such variable
>>
>> proc clamper {min max} {
>> proc clamp {varname elemname op} {
>> upvar 1 $varname var if {$op eq "write"} {
>> if {$var < $min} {
>> set var $min
>> } elseif {$var > $max} {
>> set var $max
>> }
>> }
>> }
>> return clamp
>> }
>>
>> trace add variable score write [clamper 0 20]
>>
>> set score 15 check 15 $score set score -5 check 0 $score set score 25
>> check 20 $score
>
>
> Here's how I might do this:
>
>
> proc validateRange {min max name1 name2 op} {
> if { $name2 eq "" } { ;# scalar
> upvar 1 $name1 newValue if { $newValue < $min } {
> set newValue $min
> } elseif { $newValue > $max } {
> set newValue $max
> }
> } else { ;# array - left as exercise for reader
>
> }
> }
>
> trace add variable my_percent write {validateRange 0 20 }
>
> set my_percent 10 puts "my_percent= |$my_percent| was 10"
> set my_percent 50 puts "my_percent= |$my_percent| was 50"
> set my_percent -50 puts "my_percent= |$my_percent| was -50"
>
>
> trace add variable my_percent100 write {validateRange 5 100 }
>
> set my_percent100 10 puts "my_percent100= |$my_percent100| was 10"
> set my_percent100 500 puts "my_percent100= |$my_percent100| was 500"
> set my_percent100 -50 puts "my_percent100= |$my_percent100| was -50"
>
> output:
>
> my_percent= |10| was 10 my_percent= |20| was 50 my_percent= |0| was -50
> my_percent100= |10| was 10 my_percent100= |100| was 500 my_percent100=
> |5| was -50

Ah, get that, v. clever. In the end I used this simple variation:

proc clamp {min max varname elemname op} {
upvar 1 $varname var
if {$op eq "write"} {
if {$var < $min} {
set var $min
} elseif {$var > $max} {
set var $max
}
}
}

trace add variable score write {clamp 0 20}

Thank you.

1

rocksolid light 0.9.8
clearnet tor