- Joined
- Jan 2, 2014
- Messages
- 1,790
- Reaction score
- 943
- First Language
- Chinese
- Primarily Uses
- N/A
This topic aims to incite you to share as many RGSS3 coding mistakes as you know, in order to help all of us learn from those shared mistakes, or simply make fun of them 
Let's start by sharing mine:
Not knowing Ruby variables are references
Not knowing Ruby uses short circuit evaluation
Not knowing the difference between shallow and deep copy
Not knowing the default Ruby methods are written in C
I'll continue to share more and more later. Let's share RGSS3 coding mistakes you know as well 
Let's start by sharing mine:
Not knowing Ruby variables are references
Example - Treating this:
# array_1 and array_2 refers to 2 different empty arraysarray_1 = []array_2 = []As the same as this:
array_1 = array_2 = [] # Both array_1 and array_2 refer to the same empty arrayHowever, this:
# Both array_1 and array_2 refer to what array_1 refers toarray_2 = array_1array_3 = array_1Is the same as this:
array_2 = array_3 = array_1 # Both array_1 and array_2 refer to what array_1 refers toApplication - Thinking that this method's referentially transparent:
def side_effect_free_def(array, val) # This method actually isn't side effect free temp_array = array # The passed argument array will be modified due to sort! temp_array.sort! { |a, b| a.some_attr <=> b.some_attr }.each { |obj| return obj if obj.some_attr > val } nilendWhen a truly side effect free version should be something this :
def side_effect_free_def(array, val) # This method's really side effect free array.sort { |a, b| a.some_attr <=> b.some_attr }.each { |obj| return obj if obj.some_attr > val } # sort returns a new array instead of modifying itself nilend
# array_1 and array_2 refers to 2 different empty arraysarray_1 = []array_2 = []As the same as this:
array_1 = array_2 = [] # Both array_1 and array_2 refer to the same empty arrayHowever, this:
# Both array_1 and array_2 refer to what array_1 refers toarray_2 = array_1array_3 = array_1Is the same as this:
array_2 = array_3 = array_1 # Both array_1 and array_2 refer to what array_1 refers toApplication - Thinking that this method's referentially transparent:
def side_effect_free_def(array, val) # This method actually isn't side effect free temp_array = array # The passed argument array will be modified due to sort! temp_array.sort! { |a, b| a.some_attr <=> b.some_attr }.each { |obj| return obj if obj.some_attr > val } nilendWhen a truly side effect free version should be something this :
def side_effect_free_def(array, val) # This method's really side effect free array.sort { |a, b| a.some_attr <=> b.some_attr }.each { |obj| return obj if obj.some_attr > val } # sort returns a new array instead of modifying itself nilend
Example - Treating this:
expr_1 if expr_2 || expr_3 # expr_2 will always be run but expr_3 will only be run if expr_2 returns a FalseClassAs the same as this:
expr_1 if expr_3 || expr_2 # expr_3 will always be run but expr_2 will only be run if expr_2 returns a FalseClassApplication - Writing buggy codes like this:
@var_1 ||= expr_that_shall_always_be_run # expr_that_shall_always_be_run won't run if @var_1 is already a TrueClassWhen it should be something like this:
var_1 = expr_that_shall_always_be_run # Ensures expr_that_shall_always_be_run will indeed always be run@var_1 ||= var_1
expr_1 if expr_2 || expr_3 # expr_2 will always be run but expr_3 will only be run if expr_2 returns a FalseClassAs the same as this:
expr_1 if expr_3 || expr_2 # expr_3 will always be run but expr_2 will only be run if expr_2 returns a FalseClassApplication - Writing buggy codes like this:
@var_1 ||= expr_that_shall_always_be_run # expr_that_shall_always_be_run won't run if @var_1 is already a TrueClassWhen it should be something like this:
var_1 = expr_that_shall_always_be_run # Ensures expr_that_shall_always_be_run will indeed always be run@var_1 ||= var_1
Example - Treating this:
obj_2 = obj_1.clone # Shallow copyAs the same as this:
obj_2 = Marshal.load(Marshal.dump(obj_1)) # Deep copyApplication - Thinking that the below snippet can fix the autobattle battlers having skills with custom damage formula doing things other than returning damages bug(those custom effects will be applied to real battlers if left unfixed):
class Game_Action # Edit def evaluate_item_with_target(target) # Rewrite target.result.clear # Rewritten to prevent executing any custom damage formula stuff eval_target = target.clone eval_subject = subject.clone eval_target.make_damage_value(eval_subject, item) if item.for_opponent? return eval_target.result.hp_damage.to_f / [eval_target.hp, 1].max end recovery = [-eval_target.result.hp_damage, eval_target.mhp - eval_target.hp].min.to_f / eval_target.mhp # end # evaluate_item_with_targetend # Game_ActionWhen it should be something like this:
class Game_Action # Edit def evaluate_item_with_target(target) # Rewrite target.result.clear # Rewritten to prevent executing any custom damage formula stuff eval_target = Marshal.load(Marshal.dump(target)) eval_subject = Marshal.load(Marshal.dump(subject)) eval_target.make_damage_value(eval_subject, item) if item.for_opponent? return eval_target.result.hp_damage.to_f / [eval_target.hp, 1].max end recovery = [-eval_target.result.hp_damage, eval_target.mhp - eval_target.hp].min.to_f / eval_target.mhp # end # evaluate_item_with_targetend # Game_Action
obj_2 = obj_1.clone # Shallow copyAs the same as this:
obj_2 = Marshal.load(Marshal.dump(obj_1)) # Deep copyApplication - Thinking that the below snippet can fix the autobattle battlers having skills with custom damage formula doing things other than returning damages bug(those custom effects will be applied to real battlers if left unfixed):
class Game_Action # Edit def evaluate_item_with_target(target) # Rewrite target.result.clear # Rewritten to prevent executing any custom damage formula stuff eval_target = target.clone eval_subject = subject.clone eval_target.make_damage_value(eval_subject, item) if item.for_opponent? return eval_target.result.hp_damage.to_f / [eval_target.hp, 1].max end recovery = [-eval_target.result.hp_damage, eval_target.mhp - eval_target.hp].min.to_f / eval_target.mhp # end # evaluate_item_with_targetend # Game_ActionWhen it should be something like this:
class Game_Action # Edit def evaluate_item_with_target(target) # Rewrite target.result.clear # Rewritten to prevent executing any custom damage formula stuff eval_target = Marshal.load(Marshal.dump(target)) eval_subject = Marshal.load(Marshal.dump(subject)) eval_target.make_damage_value(eval_subject, item) if item.for_opponent? return eval_target.result.hp_damage.to_f / [eval_target.hp, 1].max end recovery = [-eval_target.result.hp_damage, eval_target.mhp - eval_target.hp].min.to_f / eval_target.mhp # end # evaluate_item_with_targetend # Game_Action
Example - Thinking that the below counting sort(O(n) time complexity) will beat the default sort(O(nlogn) time complexity):
class Array def counting_sort # It's not written in C while sort is min, max = minmax counts = Array.new(max - min + 1, 0) block = -> num { counts[num - min] += 1 } each(&block) block = -> index { [index] * counts[index] } (min..max).map(&block).flatten! endendMy informal benchmark in my machine yielded this result:
test = [18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] * 1900# Around 1/10x speed of the default sortblock = -> times { test.counting_sort }p("counting_sort")1_000.times(&block)p("counting_sort")# Roughly 21 seconds# Around 10x speed of counting_sortblock = -> times { test.sort }p("sort")10_000.times(&block)p("sort")# Roughly 21 secondsApplication - I hope no one will ever "implement" this mistake lol(Such optimizations can be written in a separate dll which can be called by Ruby instead)
class Array def counting_sort # It's not written in C while sort is min, max = minmax counts = Array.new(max - min + 1, 0) block = -> num { counts[num - min] += 1 } each(&block) block = -> index { [index] * counts[index] } (min..max).map(&block).flatten! endendMy informal benchmark in my machine yielded this result:
test = [18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] * 1900# Around 1/10x speed of the default sortblock = -> times { test.counting_sort }p("counting_sort")1_000.times(&block)p("counting_sort")# Roughly 21 seconds# Around 10x speed of counting_sortblock = -> times { test.sort }p("sort")10_000.times(&block)p("sort")# Roughly 21 secondsApplication - I hope no one will ever "implement" this mistake lol(Such optimizations can be written in a separate dll which can be called by Ruby instead)
Last edited by a moderator:
