OO Challenge


H

Henry Gilbert

Dear Ruby Community,

One day I hope to learn your trade :)

But before that ...
A reasonably arrogant guy came out blasting in a web-forum about how OO is
crap and all that.

He offered a challenge which I tried to defeat but in VB.NET
Now VB.NET sucks simply because the Visual Studio IDE that comes with it
is all very boring, slow, bureacratic, clunky and when you get a spark of
inspiration it hangs saying "Please wait while we update your Help File"
(for 20 minutes)

Pure Joy-Killer

His challenge is as follows:

* I wont give the URL yet because I want you guys to come with the best
solution, don't worry I wont take credit for it - will post the website
and say this is the RUBY's solution loggin in as Anonymous *

Whole OO is step back in programming. Encapsulation is trivial
and unnecessary, inheritance wrong and polymorphism weak ..

OK, here is my favorite 'Tax Payer' challenge for OO languages. There are lot of different groups of people with different rules for tax calculation. One man can be in the same time member of many groups. His membership can change during program execution time. If he is member of many groups in the time tax is calculated, his tax is the greatest one on the base of all groups he is member (they are clever!). Natural situation, isn't it? Now, (1) define separate functions that calculate tax for each groups, and (2) write polymorphic function that calculate tax for tax payer, no matter of his membership to one or many groups in the same time. Here is code in procedural language: record tax_payer(salary,member_of)

[Version 1]

procedure tax_soldier(X)
return X.salary/10.0
end

procedure tax_professor(X)
return X.salary/15.0+100
end

#many of them ...

procedure tax(X) #procedural polymorphism
result:=0
every class:=!X.member_of do
if result then result:=t
return result
end

procedure main()
A:=tax_payer(3000,["soldier"])
B:=tax_payer(5000,["professor"])
C:=tax_payer(6000,["professor","soldier"])
#...
write(tax(A),tax(B),tax(C)) #this line is goal
end

[Added to Version 1]

Oh, board ignored part of the procedure tax(), here it is again ...

procedure tax(X)
result:=0
every class:=!X.member_of do
if result less_than t:=proc("tax_"||class)(X) then result:=t
return result
end

[Version 2]

Here is the procedural version of your second program:

record tax_payer(salary,member_of)
record tax_rule_data(multiplier, additional)
global tax_rule

procedure tax(payer)
    res:=0
    every r:=tax_rule[! payer.member_of ] do
              if res less_than t:=payer.salary/r[1]+r[2]
                                        then res:=t
    return res
end

procedure main()
    tax_rule:=table()
    tax_rule["soldier"]:=tax_rule_data(10,0)
    tax_rule["professor"]:=tax_rule_data(15,100)
    A:=tax_payer(1000,["soldier","professor"])
    write(tax(A))
end

That is actual code in Icon, not pseudocode, just like my previous program.
I believe I have my point about elegance.
I do not think that Tax Payer problem deserves to be called 'functional problem' - it is simple problem every general programming language should be able to solve easily and with elegance. Such problems are everywhere. It is not exotic automated theorem proving problem ... neither is proc() non-procedural.. actually, I remember Sinclair ZX 81 had similar GO SUB (expression) statement. Sure, it is slower, but worked well even then, on 1000 times slower comp and 20 000 times smaller memory.
Tax Payer problem is all about object (tax_payer) - class (soldier ...) membership and polimorphic functions, just it is not that simple as designers of OO languages believe (object is member of only one class (and superclasses) and does not change its membership, function version can be decided solely on class membership) - hence one is forced to handle membership relation on his own, and OO support integrated in the language is shown to be restrictive and cluttering. Proof is in the puding - compare Icon and Java code.
It is not the only problem with OO. Inheritance rules are even worse; almost everything in that concept is wild guess, and code is always much worse.
If anyone disagree and he think he has problem where OO is better, i accept the challenge.

[/UNQUOTE]


So sorry for the abuse in pasting.
Now I started solving this in VB.NET
But just to be vindictive lol .. wanted to most beautiful solution ever.
Which I believe RUBY can deliver.
This guy is talking crap.

My version in VB would be pure syntatic sugar.
But its fundamental we had an eval function
ie eval "3 + 4 / 7" returns 1
I tried to import that from JScript Library
And "bureacratic" Visual Studio started asking me to reflect on which
Engine, for which I tried to look into the help files: and it began
pissing me off with insert CD this, wait until we update your files .. and
a second time wait until we update your file, now insert CD number 2 ..
[note when I first installed I explicitily asked VS to loads ALL Library
and also saved the Library Locally but VS is just thick]

My version should have a Main more or less like:

Sub Main()

Dim ListOfTaxRules As New TaxRules
Dim ListOfTaxPayers As New TaxPayers
Dim Member As Object

With ListOfTaxTules
.Add("soldier","/10")
.Add("teacher","/15+2000")
.Add("professor","/12+1000")
End WIth

With ListOfTaxPayers
.Add("John","soldier",30000)
.Add("Mary","teacher",15000)
.Add("Gary",{"professor","soldier"},50000)
End With

For Each Member As Object In ListOfTaxPayers.List
Console.WriteLine(Member.Name,Member.CalculatedTax)
Next

End Sub

Of course I am abusing the VB.NET as Much as possible.
For the sake of readability and winning the challenge :p

I haven't supplied code for the Classes because I got stuck on importing
the Eval function from Microsoft.Jscript Library.
Which would also tarnish the "elegant" solution

There are many ways round to this problem - and the most concise and yet beautiful
easy to read .. should be considered.
So please venture completely different routes - so we can breed the best
one.

Of course his challenge is stupid, because OO languages excel on a large
scale, not on such simple things. But still I am confident there is a
solution to his silly challenge.

Thanks for your attention.
Would love to learn from you all RUBY sometime.
For another abandoned .NET project - an English Online Website
I was going to build for free - and being GPL
(Any takers? :)

All the best

Henry Gilbert
 
Ad

Advertisements

R

Robert Feldt

Henry Gilbert said:
record tax_payer(salary,member_of)
record tax_rule_data(multiplier, additional)
global tax_rule

procedure tax(payer)
    res:=0
    every r:=tax_rule[! payer.member_of ] do
              if res less_than t:=payer.salary/r[1]+r[2]
                                        then res:=t
    return res
end

procedure main()
    tax_rule:=table()
    tax_rule["soldier"]:=tax_rule_data(10,0)
    tax_rule["professor"]:=tax_rule_data(15,100)
    A:=tax_payer(1000,["soldier","professor"])
    write(tax(A))
end
Without any refactoring or rethinking of his "problem" here
is a Ruby version:

Rule = Struct.new("Rule", :multiplier, :additional)
class Rule
def calc_tax(salary)
salary/(multiplier || 1) + (additional || 0)
end
end

Rules = {"soldier" => Rule.new(10.0, 0), "professor" => Rule.new(15.0, 100)}

TaxPayer = Struct.new("TaxPayer", :salary, :member_of)
class TaxPayer
def tax
Rules.select {|n,r| member_of.include?(n)}.map do |profession, rule|
rule.calc_tax(salary)
end.max end
end

a = TaxPayer.new(1000, ["soldier", "professor"])
p a.tax # => 166.666666667

Not the way I would structure this but its close to his code.
Which one is more "elegant" is subjective IMHO but I don't think
he has got a strong case... ;)

It also seems like a lousy example for comparisons between languages
and paradigms. Then again most such comparisons are a lousy idea... ;)

Regards,

Robert
 
R

Robert Klemme

[snip]

I prefer this approach since it is more OO in the sense that rules and
their names are better bound together.

robert


require 'set'

# abstract base, not really needed
class TaxGroup
class << self
attr_reader :all_groups

def inherited(gr)
$stderr.puts "Group #{gr}"
( @all_groups ||= Set.new ) << gr
end
end
end

# tax groups
class TaxGroupSoldier < TaxGroup
def calc_tax(emp)
emp.salary/10.0
end
end

class TaxGroupProf < TaxGroup
def calc_tax(emp)
emp.salary/15.0+100
end
end

# tax payers
class TaxPayer
attr_reader :tax_groups
attr_accessor :salary

def initialize(sal, groups = [])
@salary = sal
@tax_groups = Set.new
@tax_groups.merge groups
end

def tax()
self.tax_groups.map do |gr|
gr.new.calc_tax(self)
end.max
end
end

# example
taxPayers = [
TaxPayer.new(3000,[TaxGroupSoldier]),
TaxPayer.new(5000,[TaxGroupProf]),
TaxPayer.new(6000,[TaxGroupProf, TaxGroupSoldier]),
]

taxPayers.each do |p|
puts "#{p.inspect}: #{p.tax}"
end
 
E

Eric Hodel

--/GPgYEyhnw15BExa
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
OK, here is my favorite 'Tax Payer' challenge for OO languages.
There are lot of different groups of people with different rules
for tax calculation.

Ok... Different groups of people
One man can be in the same time member of many groups.

Ok... A person is in one or more groups
If he is member of many groups in the time tax is calculated, his
tax is the greatest one on the base of all groups he is member.

Ok... A person calculates his tax based on which groups he is in.
Now, (1) define separate functions that calculate tax for each
groups, and (2) write polymorphic function that calculate tax for
tax payer, no matter of his membership to one or many groups in the
same time. Here is code in procedural language: record
tax_payer(salary,member_of)
=20
Tax Payer problem is all about object (tax_payer) - class (soldier
...) membership and polimorphic functions,

In most of the Ruby solutions, the person is the one calculating
the tax, the tax groups don't calculate how much tax a person owes.
just it is not that simple as designers of OO languages believe
(object is member of only one class (and superclasses) and does not
change its membership, function version can be decided solely on
class membership) - hence one is forced to handle membership relation
on his own, and OO support integrated in the language is shown to
be restrictive and cluttering.

A person is in one or more tax groups, which suggests that the
person should hold which professions they are in, not the other way
around. (With a trivial bit of work, you could have the profession
hold all the people who are in that profession as well, but that is not
useful for the example proposed.)
It is not the only problem with OO. Inheritance rules are even
worse; almost everything in that concept is wild guess, and code
is always much worse.

If you have to fight your language, you're doing something wrong. The
easy way is probably the right way. The real problem here seems to be
that the poster doesn't understand how to model problems in OO.

--=20
Eric Hodel - (e-mail address removed) - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04


--/GPgYEyhnw15BExa
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (FreeBSD)

iD8DBQE/YgQMMypVHHlsnwQRAlOnAKCq78so5q4US/Y7Xm6a8Dzjk+nWxQCZAX3H
wJvXFR9PdnmcbHwW4DUUdGE=
=nMz9
-----END PGP SIGNATURE-----

--/GPgYEyhnw15BExa--
 
S

Sean O'Dell

Henry said:
Dear Ruby Community,

One day I hope to learn your trade :)

But before that ...
A reasonably arrogant guy came out blasting in a web-forum about how OO is
crap and all that.

He offered a challenge which I tried to defeat but in VB.NET
Now VB.NET sucks simply because the Visual Studio IDE that comes with it
is all very boring, slow, bureacratic, clunky and when you get a spark of
inspiration it hangs saying "Please wait while we update your Help File"
(for 20 minutes)

Pure Joy-Killer

His challenge is as follows:

* I wont give the URL yet because I want you guys to come with the best
solution, don't worry I wont take credit for it - will post the website
and say this is the RUBY's solution loggin in as Anonymous *

Whole OO is step back in programming. Encapsulation is trivial
and unnecessary, inheritance wrong and polymorphism weak ..

OK, here is my favorite 'Tax Payer' challenge for OO languages. There are lot of different groups of people with different rules for tax calculation. One man can be in the same time member of many groups. His membership can change during program execution time. If he is member of many groups in the time tax is calculated, his tax is the greatest one on the base of all groups he is member (they are clever!). Natural situation, isn't it? Now, (1) define separate functions that calculate tax for each groups, and (2) write polymorphic function that calculate tax for tax payer, no matter of his membership to one or many groups in the same time. Here is code in procedural language: record tax_payer(salary,member_of)

For such a small variation, OO has little to offer. Morphing is usually
for when a class can be extended, especially when a series of extensions
can reduce code. Simply switching the tax rate between different
professions is so simple, an OO solution is likely to ADD code, not
reduce it.

However, that said, I think Ruby has a lot to offer to make this
succinct. My code is below. It's not meant to be short, it's meant to
be understandable and easily extensible.


rates = {
"soldier" => Proc.new{|salary| salary/10},
"professor" => Proc.new{|salary| (salary/15)+100}
}

taxpayers = [
{"salary" => 3000, "jobs" => ["soldier"]},
{"salary" => 5000, "jobs" => ["professor"]},
{"salary" => 6000, "jobs" => ["professor", "soldier"]}
]


taxpayers.each do | taxpayer |
tax = 0

taxpayer["jobs"].each do | job |
rate = rates[job]
raise "no such job in rate schedule: '#{job}'" if (not rate)

rate_tax = rate.call(taxpayer["salary"])

tax = rate_tax if (rate_tax > tax)
end

print(tax)
end


Sean O'Dell
 
H

Henry Gilbert

Dear Ruby Community,

One day I hope to learn your trade :)

But before that ...
A reasonably arrogant guy came out blasting in a web-forum about how OO is
crap and all that.

He offered a challenge which I tried to defeat but in VB.NET
Now VB.NET sucks simply because the Visual Studio IDE that comes with it
is all very boring, slow, bureacratic, clunky and when you get a spark of
inspiration it hangs saying "Please wait while we update your Help File"
(for 20 minutes)

Pure Joy-Killer

His challenge is as follows:

* I wont give the URL yet because I want you guys to come with the best
solution, don't worry I wont take credit for it - will post the website
and say this is the RUBY's solution loggin in as Anonymous *

Whole OO is step back in programming. Encapsulation is trivial
and unnecessary, inheritance wrong and polymorphism weak ..

OK, here is my favorite 'Tax Payer' challenge for OO languages. There are lot of different groups of people with different rules for tax calculation. One man can be in the same time member of many groups. His membership can change during program execution time. If he is member of many groups in the time tax is calculated, his tax is the greatest one on the base of all groups he is member (they are clever!). Natural situation, isn't it? Now, (1) define separate functions that calculate tax for each groups, and (2) write polymorphic function that calculate tax for tax payer, no matter of his membership to one or many groups in the same time. Here is code in procedural language: record tax_payer(salary,member_of)

[Version 1]

procedure tax_soldier(X)
return X.salary/10.0
end

procedure tax_professor(X)
return X.salary/15.0+100
end

#many of them ...

procedure tax(X) #procedural polymorphism
result:=0
every class:=!X.member_of do
if result then result:=t
return result
end

procedure main()
A:=tax_payer(3000,["soldier"])
B:=tax_payer(5000,["professor"])
C:=tax_payer(6000,["professor","soldier"])
#...
write(tax(A),tax(B),tax(C)) #this line is goal
end

[Added to Version 1]

Oh, board ignored part of the procedure tax(), here it is again ...

procedure tax(X)
result:=0
every class:=!X.member_of do
if result less_than t:=proc("tax_"||class)(X) then result:=t
return result
end

[Version 2]

Here is the procedural version of your second program:

record tax_payer(salary,member_of)
record tax_rule_data(multiplier, additional)
global tax_rule

procedure tax(payer)
    res:=0
    every r:=tax_rule[! payer.member_of ] do
              if res less_than t:=payer.salary/r[1]+r[2]
                                        then res:=t
    return res
end

procedure main()
    tax_rule:=table()
    tax_rule["soldier"]:=tax_rule_data(10,0)
    tax_rule["professor"]:=tax_rule_data(15,100)
    A:=tax_payer(1000,["soldier","professor"])
    write(tax(A))
end

That is actual code in Icon, not pseudocode, just like my previous program.
I believe I have my point about elegance.
I do not think that Tax Payer problem deserves to be called 'functional problem' - it is simple problem every general programming language should be able to solve easily and with elegance. Such problems are everywhere. It is not exotic automated theorem proving problem ... neither is proc() non-procedural.. actually, I remember Sinclair ZX 81 had similar GO SUB (expression) statement. Sure, it is slower, but worked well even then, on 1000 times slower comp and 20 000 times smaller memory.
Tax Payer problem is all about object (tax_payer) - class (soldier ...) membership and polimorphic functions, just it is not that simple as designers of OO languages believe (object is member of only one class (and superclasses) and does not change its membership, function version can be decided solely on class membership) - hence one is forced to handle membership relation on his own, and OO support integrated in the language is shown to be restrictive and cluttering. Proof is in the puding - compare Icon and Java code.
It is not the only problem with OO. Inheritance rules are even worse; almost everything in that concept is wild guess, and code is always much worse.
If anyone disagree and he think he has problem where OO is better, i accept the challenge.

[/UNQUOTE]


So sorry for the abuse in pasting.
Now I started solving this in VB.NET
But just to be vindictive lol .. wanted to most beautiful solution ever.
Which I believe RUBY can deliver.
This guy is talking crap.

My version in VB would be pure syntatic sugar.
But its fundamental we had an eval function
ie eval "3 + 4 / 7" returns 1
I tried to import that from JScript Library
And "bureacratic" Visual Studio started asking me to reflect on which
Engine, for which I tried to look into the help files: and it began
pissing me off with insert CD this, wait until we update your files .. and
a second time wait until we update your file, now insert CD number 2 ..
[note when I first installed I explicitily asked VS to loads ALL Library
and also saved the Library Locally but VS is just thick]

My version should have a Main more or less like:

Sub Main()

Dim ListOfTaxRules As New TaxRules
Dim ListOfTaxPayers As New TaxPayers
Dim Member As Object

With ListOfTaxTules
.Add("soldier","/10")
.Add("teacher","/15+2000")
.Add("professor","/12+1000")
End WIth

With ListOfTaxPayers
.Add("John","soldier",30000)
.Add("Mary","teacher",15000)
.Add("Gary",{"professor","soldier"},50000)
End With

For Each Member As Object In ListOfTaxPayers.List
Console.WriteLine(Member.Name,Member.CalculatedTax)
Next

End Sub
http://tools.devchannel.org/comment...&commentsort=0&mode=thread&tid=39&pid=179#185

And now am going to read and learn from your posts! hehe

Thanks loads for your prompt answer and enthusiam.

Henry G.



Of course I am abusing the VB.NET as Much as possible.
 
Ad

Advertisements


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top